Merge "disp: msm: dp: ensure failsafe mode in connector mode list"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
9b23a8f4aa
@@ -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;
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user