Skip to content

Commit

Permalink
drm/amd/display: Fix incorrectly pruned modes with deep color
Browse files Browse the repository at this point in the history
[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: Stylon Wang <stylon.wang@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Stylon Wang authored and alexdeucher committed May 21, 2020
1 parent fdcf62f commit cbd14ae
Showing 1 changed file with 64 additions and 38 deletions.
102 changes: 64 additions & 38 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
Expand Up @@ -3840,8 +3840,7 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,

static enum dc_color_depth
convert_color_depth_from_display_info(const struct drm_connector *connector,
const struct drm_connector_state *state,
bool is_y420)
bool is_y420, int requested_bpc)
{
uint8_t bpc;

Expand All @@ -3861,10 +3860,7 @@ convert_color_depth_from_display_info(const struct drm_connector *connector,
bpc = bpc ? bpc : 8;
}

if (!state)
state = connector->state;

if (state) {
if (requested_bpc > 0) {
/*
* Cap display bpc based on the user requested value.
*
Expand All @@ -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
* 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. */
bpc = bpc - (bpc & 1);
Expand Down Expand Up @@ -3995,7 +3991,8 @@ static void fill_stream_properties_from_drm_display_mode(
const struct drm_display_mode *mode_in,
const struct drm_connector *connector,
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;
const struct drm_display_info *info = &connector->display_info;
Expand Down Expand Up @@ -4025,8 +4022,9 @@ static void fill_stream_properties_from_drm_display_mode(

timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
timing_out->display_color_depth = convert_color_depth_from_display_info(
connector, connector_state,
(timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420));
connector,
(timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420),
requested_bpc);
timing_out->scan_type = SCANNING_TYPE_NODATA;
timing_out->hdmi_vic = 0;

Expand Down Expand Up @@ -4232,7 +4230,8 @@ static struct dc_stream_state *
create_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)
const struct dc_stream_state *old_stream,
int requested_bpc)
{
struct drm_display_mode *preferred_mode = NULL;
struct drm_connector *drm_connector;
Expand Down Expand Up @@ -4317,10 +4316,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
*/
if (!scale || mode_refresh != preferred_refresh)
fill_stream_properties_from_drm_display_mode(stream,
&mode, &aconnector->base, con_state, NULL);
&mode, &aconnector->base, con_state, NULL, requested_bpc);
else
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;

Expand Down Expand Up @@ -4839,16 +4838,54 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *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,
struct drm_display_mode *mode)
{
int result = MODE_ERROR;
struct dc_sink *dc_sink;
struct amdgpu_device *adev = connector->dev->dev_private;
/* TODO: Unhardcode stream count */
struct dc_stream_state *stream;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
enum dc_status dc_result = DC_OK;

if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(mode->flags & DRM_MODE_FLAG_DBLSCAN))
Expand All @@ -4869,24 +4906,11 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
goto fail;
}

stream = create_stream_for_sink(aconnector, mode, NULL, NULL);
if (stream == NULL) {
DRM_ERROR("Failed to create stream for sink!\n");
goto fail;
}

dc_result = dc_validate_stream(adev->dm.dc, stream);

if (dc_result == DC_OK)
stream = create_validate_stream_for_sink(aconnector, mode, NULL, NULL);
if (stream) {
dc_stream_release(stream);
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:
/* TODO: error handling*/
Expand Down Expand Up @@ -5209,10 +5233,12 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
return 0;

if (!state->duplicated) {
int max_bpc = conn_state->max_requested_bpc;
is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
aconnector->force_yuv420_output;
color_depth = convert_color_depth_from_display_info(connector, conn_state,
is_y420);
color_depth = convert_color_depth_from_display_info(connector,
is_y420,
max_bpc);
bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
clock = adjusted_mode->clock;
dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false);
Expand Down Expand Up @@ -7642,10 +7668,10 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
goto skip_modeset;

new_stream = create_stream_for_sink(aconnector,
&new_crtc_state->mode,
dm_new_conn_state,
dm_old_crtc_state->stream);
new_stream = create_validate_stream_for_sink(aconnector,
&new_crtc_state->mode,
dm_new_conn_state,
dm_old_crtc_state->stream);

/*
* we can have no stream on ACTION_SET if a display
Expand Down

0 comments on commit cbd14ae

Please sign in to comment.