diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index d9f0cef4a8..cf06d903ad 100644 --- a/msm/dp/dp_display.c +++ b/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; diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 5180209202..60b20b27ef 100644 --- a/msm/dp/dp_drm.c +++ b/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"); } diff --git a/msm/dp/dp_drm.h b/msm/dp/dp_drm.h index 2890467131..6ceb3ab3f8 100644 --- a/msm/dp/dp_drm.h +++ b/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) diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index 75d13ad916..1441dce812 100644 --- a/msm/dp/dp_mst_drm.c +++ b/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); } diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 16caf232c7..28a754f081 100644 --- a/msm/dp/dp_panel.c +++ b/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)