Commit cbd14ae7 authored by Stylon Wang's avatar Stylon Wang Committed by Alex Deucher

drm/amd/display: Fix incorrectly pruned modes with deep color

[Why]
When "max bpc" is set to enable deep color, some modes are removed from
the list if they fail validation on max bpc. These modes should be kept
if they validates fine with lower bpc.

[How]
- Retry with lower bpc in mode validation.
- Same in atomic commit to apply working bpc, not necessarily max bpc.
Signed-off-by: default avatarStylon Wang <stylon.wang@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent fdcf62fb
...@@ -3840,8 +3840,7 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, ...@@ -3840,8 +3840,7 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,
static enum dc_color_depth static enum dc_color_depth
convert_color_depth_from_display_info(const struct drm_connector *connector, convert_color_depth_from_display_info(const struct drm_connector *connector,
const struct drm_connector_state *state, bool is_y420, int requested_bpc)
bool is_y420)
{ {
uint8_t bpc; uint8_t bpc;
...@@ -3861,10 +3860,7 @@ convert_color_depth_from_display_info(const struct drm_connector *connector, ...@@ -3861,10 +3860,7 @@ convert_color_depth_from_display_info(const struct drm_connector *connector,
bpc = bpc ? bpc : 8; bpc = bpc ? bpc : 8;
} }
if (!state) if (requested_bpc > 0) {
state = connector->state;
if (state) {
/* /*
* Cap display bpc based on the user requested value. * Cap display bpc based on the user requested value.
* *
...@@ -3873,7 +3869,7 @@ convert_color_depth_from_display_info(const struct drm_connector *connector, ...@@ -3873,7 +3869,7 @@ convert_color_depth_from_display_info(const struct drm_connector *connector,
* or if this was called outside of atomic check, so it * or if this was called outside of atomic check, so it
* can't be used directly. * can't be used directly.
*/ */
bpc = min(bpc, state->max_requested_bpc); bpc = min_t(u8, bpc, requested_bpc);
/* Round down to the nearest even number. */ /* Round down to the nearest even number. */
bpc = bpc - (bpc & 1); bpc = bpc - (bpc & 1);
...@@ -3995,7 +3991,8 @@ static void fill_stream_properties_from_drm_display_mode( ...@@ -3995,7 +3991,8 @@ static void fill_stream_properties_from_drm_display_mode(
const struct drm_display_mode *mode_in, const struct drm_display_mode *mode_in,
const struct drm_connector *connector, const struct drm_connector *connector,
const struct drm_connector_state *connector_state, const struct drm_connector_state *connector_state,
const struct dc_stream_state *old_stream) const struct dc_stream_state *old_stream,
int requested_bpc)
{ {
struct dc_crtc_timing *timing_out = &stream->timing; struct dc_crtc_timing *timing_out = &stream->timing;
const struct drm_display_info *info = &connector->display_info; const struct drm_display_info *info = &connector->display_info;
...@@ -4025,8 +4022,9 @@ static void fill_stream_properties_from_drm_display_mode( ...@@ -4025,8 +4022,9 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
timing_out->display_color_depth = convert_color_depth_from_display_info( timing_out->display_color_depth = convert_color_depth_from_display_info(
connector, connector_state, connector,
(timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)); (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420),
requested_bpc);
timing_out->scan_type = SCANNING_TYPE_NODATA; timing_out->scan_type = SCANNING_TYPE_NODATA;
timing_out->hdmi_vic = 0; timing_out->hdmi_vic = 0;
...@@ -4232,7 +4230,8 @@ static struct dc_stream_state * ...@@ -4232,7 +4230,8 @@ static struct dc_stream_state *
create_stream_for_sink(struct amdgpu_dm_connector *aconnector, create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct drm_display_mode *drm_mode, const struct drm_display_mode *drm_mode,
const struct dm_connector_state *dm_state, const struct dm_connector_state *dm_state,
const struct dc_stream_state *old_stream) const struct dc_stream_state *old_stream,
int requested_bpc)
{ {
struct drm_display_mode *preferred_mode = NULL; struct drm_display_mode *preferred_mode = NULL;
struct drm_connector *drm_connector; struct drm_connector *drm_connector;
...@@ -4317,10 +4316,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, ...@@ -4317,10 +4316,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
*/ */
if (!scale || mode_refresh != preferred_refresh) if (!scale || mode_refresh != preferred_refresh)
fill_stream_properties_from_drm_display_mode(stream, fill_stream_properties_from_drm_display_mode(stream,
&mode, &aconnector->base, con_state, NULL); &mode, &aconnector->base, con_state, NULL, requested_bpc);
else else
fill_stream_properties_from_drm_display_mode(stream, fill_stream_properties_from_drm_display_mode(stream,
&mode, &aconnector->base, con_state, old_stream); &mode, &aconnector->base, con_state, old_stream, requested_bpc);
stream->timing.flags.DSC = 0; stream->timing.flags.DSC = 0;
...@@ -4839,16 +4838,54 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) ...@@ -4839,16 +4838,54 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
create_eml_sink(aconnector); create_eml_sink(aconnector);
} }
static struct dc_stream_state *
create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct drm_display_mode *drm_mode,
const struct dm_connector_state *dm_state,
const struct dc_stream_state *old_stream)
{
struct drm_connector *connector = &aconnector->base;
struct amdgpu_device *adev = connector->dev->dev_private;
struct dc_stream_state *stream;
int requested_bpc = connector->state ? connector->state->max_requested_bpc : 8;
enum dc_status dc_result = DC_OK;
do {
stream = create_stream_for_sink(aconnector, drm_mode,
dm_state, old_stream,
requested_bpc);
if (stream == NULL) {
DRM_ERROR("Failed to create stream for sink!\n");
break;
}
dc_result = dc_validate_stream(adev->dm.dc, stream);
if (dc_result != DC_OK) {
DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n",
drm_mode->hdisplay,
drm_mode->vdisplay,
drm_mode->clock,
dc_result);
dc_stream_release(stream);
stream = NULL;
requested_bpc -= 2; /* lower bpc to retry validation */
}
} while (stream == NULL && requested_bpc >= 6);
return stream;
}
enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
int result = MODE_ERROR; int result = MODE_ERROR;
struct dc_sink *dc_sink; struct dc_sink *dc_sink;
struct amdgpu_device *adev = connector->dev->dev_private;
/* TODO: Unhardcode stream count */ /* TODO: Unhardcode stream count */
struct dc_stream_state *stream; struct dc_stream_state *stream;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
enum dc_status dc_result = DC_OK;
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(mode->flags & DRM_MODE_FLAG_DBLSCAN)) (mode->flags & DRM_MODE_FLAG_DBLSCAN))
...@@ -4869,24 +4906,11 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec ...@@ -4869,24 +4906,11 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
goto fail; goto fail;
} }
stream = create_stream_for_sink(aconnector, mode, NULL, NULL); stream = create_validate_stream_for_sink(aconnector, mode, NULL, NULL);
if (stream == NULL) { if (stream) {
DRM_ERROR("Failed to create stream for sink!\n"); dc_stream_release(stream);
goto fail;
}
dc_result = dc_validate_stream(adev->dm.dc, stream);
if (dc_result == DC_OK)
result = MODE_OK; result = MODE_OK;
else }
DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n",
mode->hdisplay,
mode->vdisplay,
mode->clock,
dc_result);
dc_stream_release(stream);
fail: fail:
/* TODO: error handling*/ /* TODO: error handling*/
...@@ -5209,10 +5233,12 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, ...@@ -5209,10 +5233,12 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
return 0; return 0;
if (!state->duplicated) { if (!state->duplicated) {
int max_bpc = conn_state->max_requested_bpc;
is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
aconnector->force_yuv420_output; aconnector->force_yuv420_output;
color_depth = convert_color_depth_from_display_info(connector, conn_state, color_depth = convert_color_depth_from_display_info(connector,
is_y420); is_y420,
max_bpc);
bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
clock = adjusted_mode->clock; clock = adjusted_mode->clock;
dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false);
...@@ -7642,10 +7668,10 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, ...@@ -7642,10 +7668,10 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
goto skip_modeset; goto skip_modeset;
new_stream = create_stream_for_sink(aconnector, new_stream = create_validate_stream_for_sink(aconnector,
&new_crtc_state->mode, &new_crtc_state->mode,
dm_new_conn_state, dm_new_conn_state,
dm_old_crtc_state->stream); dm_old_crtc_state->stream);
/* /*
* we can have no stream on ACTION_SET if a display * we can have no stream on ACTION_SET if a display
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment