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;
 
                bpc = bpc ? bpc : 8;
        }
 
-       if (!state)
-               state = connector->state;
-
-       if (state) {
+       if (requested_bpc > 0) {
                /*
                 * Cap display bpc based on the user requested value.
                 *
                 * 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);
        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;
 
        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;
 
 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;
        */
        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;
 
        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))
                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*/
                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);
                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