Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index 8b4b186c57f515fd541eaa15ce55e0b3ebf2dadb..b6bef202b6bbbc841f8928153567e0181d29fb9c 100644 (file)
@@ -365,6 +365,14 @@ static inline void reverse_planes_order(struct dc_surface_update *array_of_surfa
  * adjustments and preparation before calling it. This function is a wrapper
  * for the dc_update_planes_and_stream that does any required configuration
  * before passing control to DC.
+ *
+ * @dc: Display Core control structure
+ * @update_type: specify whether it is FULL/MEDIUM/FAST update
+ * @planes_count: planes count to update
+ * @stream: stream state
+ * @stream_update: stream update
+ * @array_of_surface_update: dc surface update pointer
+ *
  */
 static inline bool update_planes_and_stream_adapter(struct dc *dc,
                                                    int update_type,
@@ -1646,11 +1654,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
                init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;
 
-       /* Disable SubVP + DRR config by default */
-       init_data.flags.disable_subvp_drr = true;
-       if (amdgpu_dc_feature_mask & DC_ENABLE_SUBVP_DRR)
-               init_data.flags.disable_subvp_drr = false;
-
        init_data.flags.seamless_boot_edp_requested = false;
 
        if (check_seamless_boot_capability(adev)) {
@@ -1672,9 +1675,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        adev->dm.dc = dc_create(&init_data);
 
        if (adev->dm.dc) {
-               DRM_INFO("Display Core initialized with v%s!\n", DC_VER);
+               DRM_INFO("Display Core v%s initialized on %s\n", DC_VER,
+                        dce_version_to_string(adev->dm.dc->ctx->dce_version));
        } else {
-               DRM_INFO("Display Core failed to initialize with v%s!\n", DC_VER);
+               DRM_INFO("Display Core v%s failed to initialize on %s\n", DC_VER,
+                        dce_version_to_string(adev->dm.dc->ctx->dce_version));
                goto error;
        }
 
@@ -1776,12 +1781,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 
                dc_init_callbacks(adev->dm.dc, &init_params);
        }
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-       adev->dm.secure_display_ctxs = amdgpu_dm_crtc_secure_display_create_contexts(adev);
-       if (!adev->dm.secure_display_ctxs) {
-               DRM_ERROR("amdgpu: failed to initialize secure_display_ctxs.\n");
-       }
-#endif
        if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
                init_completion(&adev->dm.dmub_aux_transfer_done);
                adev->dm.dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_KERNEL);
@@ -1840,6 +1839,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                goto error;
        }
 
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+       adev->dm.secure_display_ctxs = amdgpu_dm_crtc_secure_display_create_contexts(adev);
+       if (!adev->dm.secure_display_ctxs)
+               DRM_ERROR("amdgpu: failed to initialize secure display contexts.\n");
+#endif
 
        DRM_DEBUG_DRIVER("KMS initialized.\n");
 
@@ -2479,20 +2483,25 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
                if (acrtc && state->stream_status[i].plane_count != 0) {
                        irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
                        rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
-                       DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
-                                     acrtc->crtc_id, enable ? "en" : "dis", rc);
                        if (rc)
                                DRM_WARN("Failed to %s pflip interrupts\n",
                                         enable ? "enable" : "disable");
 
                        if (enable) {
-                               rc = amdgpu_dm_crtc_enable_vblank(&acrtc->base);
-                               if (rc)
-                                       DRM_WARN("Failed to enable vblank interrupts\n");
-                       } else {
-                               amdgpu_dm_crtc_disable_vblank(&acrtc->base);
-                       }
+                               if (amdgpu_dm_crtc_vrr_active(to_dm_crtc_state(acrtc->base.state)))
+                                       rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true);
+                       } else
+                               rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, false);
+
+                       if (rc)
+                               DRM_WARN("Failed to %sable vupdate interrupt\n", enable ? "en" : "dis");
 
+                       irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
+                       /* During gpu-reset we disable and then enable vblank irq, so
+                        * don't use amdgpu_irq_get/put() to avoid refcount change.
+                        */
+                       if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
+                               DRM_WARN("Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
                }
        }
 
@@ -2852,7 +2861,7 @@ static int dm_resume(void *handle)
                 * this is the case when traversing through already created
                 * MST connectors, should be skipped
                 */
-               if (aconnector->dc_link->type == dc_connection_mst_branch)
+               if (aconnector && aconnector->mst_root)
                        continue;
 
                mutex_lock(&aconnector->hpd_lock);
@@ -5326,21 +5335,44 @@ get_aspect_ratio(const struct drm_display_mode *mode_in)
 }
 
 static enum dc_color_space
-get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing)
+get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
+                      const struct drm_connector_state *connector_state)
 {
        enum dc_color_space color_space = COLOR_SPACE_SRGB;
 
-       switch (dc_crtc_timing->pixel_encoding) {
-       case PIXEL_ENCODING_YCBCR422:
-       case PIXEL_ENCODING_YCBCR444:
-       case PIXEL_ENCODING_YCBCR420:
-       {
+       switch (connector_state->colorspace) {
+       case DRM_MODE_COLORIMETRY_BT601_YCC:
+               if (dc_crtc_timing->flags.Y_ONLY)
+                       color_space = COLOR_SPACE_YCBCR601_LIMITED;
+               else
+                       color_space = COLOR_SPACE_YCBCR601;
+               break;
+       case DRM_MODE_COLORIMETRY_BT709_YCC:
+               if (dc_crtc_timing->flags.Y_ONLY)
+                       color_space = COLOR_SPACE_YCBCR709_LIMITED;
+               else
+                       color_space = COLOR_SPACE_YCBCR709;
+               break;
+       case DRM_MODE_COLORIMETRY_OPRGB:
+               color_space = COLOR_SPACE_ADOBERGB;
+               break;
+       case DRM_MODE_COLORIMETRY_BT2020_RGB:
+       case DRM_MODE_COLORIMETRY_BT2020_YCC:
+               if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
+                       color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
+               else
+                       color_space = COLOR_SPACE_2020_YCBCR;
+               break;
+       case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601
+       default:
+               if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
+                       color_space = COLOR_SPACE_SRGB;
                /*
                 * 27030khz is the separation point between HDTV and SDTV
                 * according to HDMI spec, we use YCbCr709 and YCbCr601
                 * respectively
                 */
-               if (dc_crtc_timing->pix_clk_100hz > 270300) {
+               } else if (dc_crtc_timing->pix_clk_100hz > 270300) {
                        if (dc_crtc_timing->flags.Y_ONLY)
                                color_space =
                                        COLOR_SPACE_YCBCR709_LIMITED;
@@ -5353,15 +5385,6 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing)
                        else
                                color_space = COLOR_SPACE_YCBCR601;
                }
-
-       }
-       break;
-       case PIXEL_ENCODING_RGB:
-               color_space = COLOR_SPACE_SRGB;
-               break;
-
-       default:
-               WARN_ON(1);
                break;
        }
 
@@ -5500,7 +5523,7 @@ static void fill_stream_properties_from_drm_display_mode(
                }
        }
 
-       stream->output_color_space = get_output_color_space(timing_out);
+       stream->output_color_space = get_output_color_space(timing_out, connector_state);
 }
 
 static void fill_audio_info(struct audio_info *audio_info,
@@ -5942,15 +5965,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 {
        struct drm_display_mode *preferred_mode = NULL;
        struct drm_connector *drm_connector;
-       const struct drm_connector_state *con_state =
-               dm_state ? &dm_state->base : NULL;
+       const struct drm_connector_state *con_state = &dm_state->base;
        struct dc_stream_state *stream = NULL;
        struct drm_display_mode mode;
        struct drm_display_mode saved_mode;
        struct drm_display_mode *freesync_mode = NULL;
        bool native_mode_found = false;
        bool recalculate_timing = false;
-       bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false;
+       bool scale = dm_state->scaling != RMX_OFF;
        int mode_refresh;
        int preferred_refresh = 0;
        enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
@@ -6013,8 +6035,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                 */
                DRM_DEBUG_DRIVER("No preferred mode found\n");
        } else {
-               recalculate_timing = amdgpu_freesync_vid_mode &&
-                                is_freesync_video_mode(&mode, aconnector);
+               recalculate_timing = is_freesync_video_mode(&mode, aconnector);
                if (recalculate_timing) {
                        freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
                        drm_mode_copy(&saved_mode, &mode);
@@ -6029,7 +6050,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 
        if (recalculate_timing)
                drm_mode_set_crtcinfo(&saved_mode, 0);
-       else if (!dm_state)
+       else
                drm_mode_set_crtcinfo(&mode, 0);
 
        /*
@@ -6342,6 +6363,31 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
        return 0;
 }
 
+static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
+{
+       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+       struct dc_link *dc_link = aconnector->dc_link;
+       struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
+       struct edid *edid;
+
+       if (!connector->edid_override)
+               return;
+
+       drm_edid_override_connector_update(&aconnector->base);
+       edid = aconnector->base.edid_blob_ptr->data;
+       aconnector->edid = edid;
+
+       /* Update emulated (virtual) sink's EDID */
+       if (dc_em_sink && dc_link) {
+               memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
+               memmove(dc_em_sink->dc_edid.raw_edid, edid, (edid->extensions + 1) * EDID_LENGTH);
+               dm_helpers_parse_edid_caps(
+                       dc_link,
+                       &dc_em_sink->dc_edid,
+                       &dc_em_sink->edid_caps);
+       }
+}
+
 static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
        .reset = amdgpu_dm_connector_funcs_reset,
        .detect = amdgpu_dm_connector_detect,
@@ -6352,7 +6398,8 @@ static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
        .atomic_set_property = amdgpu_dm_connector_atomic_set_property,
        .atomic_get_property = amdgpu_dm_connector_atomic_get_property,
        .late_register = amdgpu_dm_connector_late_register,
-       .early_unregister = amdgpu_dm_connector_unregister
+       .early_unregister = amdgpu_dm_connector_unregister,
+       .force = amdgpu_dm_connector_funcs_force
 };
 
 static int get_modes(struct drm_connector *connector)
@@ -6369,11 +6416,19 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
        struct edid *edid;
 
        if (!aconnector->base.edid_blob_ptr) {
-               DRM_ERROR("No EDID firmware found on connector: %s ,forcing to OFF!\n",
-                               aconnector->base.name);
+               /* if connector->edid_override valid, pass
+                * it to edid_override to edid_blob_ptr
+                */
 
-               aconnector->base.force = DRM_FORCE_OFF;
-               return;
+               drm_edid_override_connector_update(&aconnector->base);
+
+               if (!aconnector->base.edid_blob_ptr) {
+                       DRM_ERROR("No EDID firmware found on connector: %s ,forcing to OFF!\n",
+                                       aconnector->base.name);
+
+                       aconnector->base.force = DRM_FORCE_OFF;
+                       return;
+               }
        }
 
        edid = (struct edid *) aconnector->base.edid_blob_ptr->data;
@@ -6558,7 +6613,9 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
                goto fail;
        }
 
-       stream = create_validate_stream_for_sink(aconnector, mode, NULL, NULL);
+       stream = create_validate_stream_for_sink(aconnector, mode,
+                                                to_dm_connector_state(connector->state),
+                                                NULL);
        if (stream) {
                dc_stream_release(stream);
                result = MODE_OK;
@@ -6652,6 +6709,14 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
        if (!crtc)
                return 0;
 
+       if (new_con_state->colorspace != old_con_state->colorspace) {
+               new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
+               if (IS_ERR(new_crtc_state))
+                       return PTR_ERR(new_crtc_state);
+
+               new_crtc_state->mode_changed = true;
+       }
+
        if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) {
                struct dc_info_packet hdr_infopacket;
 
@@ -6674,7 +6739,7 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
                 * set is permissible, however. So only force a
                 * modeset if we're entering or exiting HDR.
                 */
-               new_crtc_state->mode_changed =
+               new_crtc_state->mode_changed = new_crtc_state->mode_changed ||
                        !old_con_state->hdr_output_metadata ||
                        !new_con_state->hdr_output_metadata;
        }
@@ -6737,7 +6802,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
        int clock, bpp = 0;
        bool is_y420 = false;
 
-       if (!aconnector->mst_output_port || !aconnector->dc_sink)
+       if (!aconnector->mst_output_port)
                return 0;
 
        mst_port = aconnector->mst_output_port;
@@ -7163,7 +7228,7 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                to_amdgpu_dm_connector(connector);
 
-       if (!(amdgpu_freesync_vid_mode && edid))
+       if (!edid)
                return;
 
        if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
@@ -7199,6 +7264,12 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
        return amdgpu_dm_connector->num_modes;
 }
 
+static const u32 supported_colorspaces =
+       BIT(DRM_MODE_COLORIMETRY_BT709_YCC) |
+       BIT(DRM_MODE_COLORIMETRY_OPRGB) |
+       BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) |
+       BIT(DRM_MODE_COLORIMETRY_BT2020_YCC);
+
 void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                     struct amdgpu_dm_connector *aconnector,
                                     int connector_type,
@@ -7279,6 +7350,15 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.abm_level_property, 0);
        }
 
+       if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
+               if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces))
+                       drm_connector_attach_colorspace_property(&aconnector->base);
+       } else if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+                  connector_type == DRM_MODE_CONNECTOR_eDP) {
+               if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces))
+                       drm_connector_attach_colorspace_property(&aconnector->base);
+       }
+
        if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
            connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
            connector_type == DRM_MODE_CONNECTOR_eDP) {
@@ -9208,8 +9288,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                 * TODO: Refactor this function to allow this check to work
                 * in all conditions.
                 */
-               if (amdgpu_freesync_vid_mode &&
-                   dm_new_crtc_state->stream &&
+               if (dm_new_crtc_state->stream &&
                    is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
                        goto skip_modeset;
 
@@ -9251,7 +9330,9 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                }
 
                /* Now check if we should set freesync video mode */
-               if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
+               if (dm_new_crtc_state->stream &&
+                   dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
+                   dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream) &&
                    is_timing_unchanged_for_freesync(new_crtc_state,
                                                     old_crtc_state)) {
                        new_crtc_state->mode_changed = false;
@@ -9263,7 +9344,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                        set_freesync_fixed_config(dm_new_crtc_state);
 
                        goto skip_modeset;
-               } else if (amdgpu_freesync_vid_mode && aconnector &&
+               } else if (aconnector &&
                           is_freesync_video_mode(&new_crtc_state->mode,
                                                  aconnector)) {
                        struct drm_display_mode *high_mode;
@@ -10323,7 +10404,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
        input->cea_total_length = total_length;
        memcpy(input->payload, data, length);
 
-       res = dc_dmub_srv_cmd_with_reply_data(dm->dc->ctx->dmub_srv, &cmd);
+       res = dm_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
        if (!res) {
                DRM_ERROR("EDID CEA parser failed\n");
                return false;
@@ -10773,3 +10854,13 @@ bool check_seamless_boot_capability(struct amdgpu_device *adev)
 
        return false;
 }
+
+bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
+{
+       return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
+}
+
+bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
+{
+       return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type);
+}