]> Git Repo - linux.git/blobdiff - drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
Merge tag 'drm-xe-next-2023-12-21-pr1-1' of https://gitlab.freedesktop.org/drm/xe...
[linux.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index ee97814ebd994721f4cb161b0e3df40693086265..54861136dafd911461f8de9f0e5cbc36282dfab2 100644 (file)
@@ -54,6 +54,7 @@
 #include "amdgpu_dm_crtc.h"
 #include "amdgpu_dm_hdcp.h"
 #include <drm/display/drm_hdcp_helper.h>
+#include "amdgpu_dm_wb.h"
 #include "amdgpu_pm.h"
 #include "amdgpu_atombios.h"
 
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_blend.h>
+#include <drm/drm_fixed.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_eld.h>
 #include <drm/drm_vblank.h>
 #include <drm/drm_audio_component.h>
 #include <drm/drm_gem_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
 
 #include <acpi/video.h>
 
@@ -575,6 +577,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
 {
        struct common_irq_params *irq_params = interrupt_params;
        struct amdgpu_device *adev = irq_params->adev;
+       struct drm_writeback_job *job;
        struct amdgpu_crtc *acrtc;
        unsigned long flags;
        int vrr_active;
@@ -583,6 +586,33 @@ static void dm_crtc_high_irq(void *interrupt_params)
        if (!acrtc)
                return;
 
+       if (acrtc->wb_pending) {
+               if (acrtc->wb_conn) {
+                       spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
+                       job = list_first_entry_or_null(&acrtc->wb_conn->job_queue,
+                                                      struct drm_writeback_job,
+                                                      list_entry);
+                       spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
+
+                       if (job) {
+                               unsigned int v_total, refresh_hz;
+                               struct dc_stream_state *stream = acrtc->dm_irq_params.stream;
+
+                               v_total = stream->adjust.v_total_max ?
+                                         stream->adjust.v_total_max : stream->timing.v_total;
+                               refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz *
+                                            100LL, (v_total * stream->timing.h_total));
+                               mdelay(1000 / refresh_hz);
+
+                               drm_writeback_signal_completion(acrtc->wb_conn, 0);
+                               dc_stream_fc_disable_writeback(adev->dm.dc,
+                                                              acrtc->dm_irq_params.stream, 0);
+                       }
+               } else
+                       DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__);
+               acrtc->wb_pending = false;
+       }
+
        vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
 
        drm_dbg_vbl(adev_to_drm(adev),
@@ -725,6 +755,10 @@ static void dmub_hpd_callback(struct amdgpu_device *adev,
 
        drm_connector_list_iter_begin(dev, &iter);
        drm_for_each_connector_iter(connector, &iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                if (link && aconnector->dc_link == link) {
                        if (notify->type == DMUB_NOTIFICATION_HPD)
@@ -894,8 +928,7 @@ static int dm_early_init(void *handle);
 /* Allocate memory for FBC compressed data  */
 static void amdgpu_dm_fbc_init(struct drm_connector *connector)
 {
-       struct drm_device *dev = connector->dev;
-       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct amdgpu_device *adev = drm_to_adev(connector->dev);
        struct dm_compressor_info *compressor = &adev->dm.compressor;
        struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
        struct drm_display_mode *mode;
@@ -949,6 +982,10 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
 
        drm_connector_list_iter_begin(dev, &conn_iter);
        drm_for_each_connector_iter(connector, &conn_iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                if (aconnector->audio_inst != port)
                        continue;
@@ -989,8 +1026,7 @@ static int amdgpu_dm_audio_component_bind(struct device *kdev,
 static void amdgpu_dm_audio_component_unbind(struct device *kdev,
                                          struct device *hda_kdev, void *data)
 {
-       struct drm_device *dev = dev_get_drvdata(kdev);
-       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
        struct drm_audio_component *acomp = data;
 
        acomp->ops = NULL;
@@ -1675,6 +1711,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0];
        init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0];
 
+       /* Enable DWB for tested platforms only */
+       if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0))
+               init_data.num_virtual_links = 1;
+
        INIT_LIST_HEAD(&adev->dm.da_list);
 
        retrieve_dmi_info(&adev->dm);
@@ -1717,23 +1757,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        /* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
        adev->dm.dc->debug.ignore_cable_id = true;
 
-       /* TODO: There is a new drm mst change where the freedom of
-        * vc_next_start_slot update is revoked/moved into drm, instead of in
-        * driver. This forces us to make sure to get vc_next_start_slot updated
-        * in drm function each time without considering if mst_state is active
-        * or not. Otherwise, next time hotplug will give wrong start_slot
-        * number. We are implementing a temporary solution to even notify drm
-        * mst deallocation when link is no longer of MST type when uncommitting
-        * the stream so we will have more time to work on a proper solution.
-        * Ideally when dm_helpers_dp_mst_stop_top_mgr message is triggered, we
-        * should notify drm to do a complete "reset" of its states and stop
-        * calling further drm mst functions when link is no longer of an MST
-        * type. This could happen when we unplug an MST hubs/displays. When
-        * uncommit stream comes later after unplug, we should just reset
-        * hardware states only.
-        */
-       adev->dm.dc->debug.temp_mst_deallocation_sequence = true;
-
        if (adev->dm.dc->caps.dp_hdmi21_pcon_support)
                DRM_INFO("DP-HDMI FRL PCON supported\n");
 
@@ -2269,6 +2292,10 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev)
 
        drm_connector_list_iter_begin(dev, &iter);
        drm_for_each_connector_iter(connector, &iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                if (aconnector->dc_link->type == dc_connection_mst_branch &&
                    aconnector->mst_mgr.aux) {
@@ -2397,6 +2424,10 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
 
        drm_connector_list_iter_begin(dev, &iter);
        drm_for_each_connector_iter(connector, &iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                if (aconnector->dc_link->type != dc_connection_mst_branch ||
                    aconnector->mst_root)
@@ -2656,11 +2687,12 @@ static int dm_suspend(void *handle)
        hpd_rx_irq_work_suspend(dm);
 
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
+       dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D3);
 
        return 0;
 }
 
-struct amdgpu_dm_connector *
+struct drm_connector *
 amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
                                             struct drm_crtc *crtc)
 {
@@ -2673,7 +2705,7 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
                crtc_from_state = new_con_state->crtc;
 
                if (crtc_from_state == crtc)
-                       return to_amdgpu_dm_connector(connector);
+                       return connector;
        }
 
        return NULL;
@@ -2851,6 +2883,7 @@ static int dm_resume(void *handle)
                if (r)
                        DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
 
+               dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0);
                dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
 
                dc_resume(dm->dc);
@@ -2901,6 +2934,7 @@ static int dm_resume(void *handle)
        }
 
        /* power on hardware */
+       dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0);
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
 
        /* program HPD filter */
@@ -2918,6 +2952,10 @@ static int dm_resume(void *handle)
        /* Do detection*/
        drm_connector_list_iter_begin(ddev, &iter);
        drm_for_each_connector_iter(connector, &iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
 
                if (!aconnector->dc_link)
@@ -3491,6 +3529,9 @@ static void register_hpd_handlers(struct amdgpu_device *adev)
        list_for_each_entry(connector,
                        &dev->mode_config.connector_list, head) {
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                dc_link = aconnector->dc_link;
 
@@ -4029,6 +4070,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
                return r;
        }
 
+#ifdef AMD_PRIVATE_COLOR
+       if (amdgpu_dm_create_color_properties(adev))
+               return -ENOMEM;
+#endif
+
        r = amdgpu_dm_audio_init(adev);
        if (r) {
                dc_release_state(state->context);
@@ -4482,6 +4528,28 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                        continue;
                }
 
+               link = dc_get_link_at_index(dm->dc, i);
+
+               if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) {
+                       struct amdgpu_dm_wb_connector *wbcon = kzalloc(sizeof(*wbcon), GFP_KERNEL);
+
+                       if (!wbcon) {
+                               DRM_ERROR("KMS: Failed to allocate writeback connector\n");
+                               continue;
+                       }
+
+                       if (amdgpu_dm_wb_connector_init(dm, wbcon, i)) {
+                               DRM_ERROR("KMS: Failed to initialize writeback connector\n");
+                               kfree(wbcon);
+                               continue;
+                       }
+
+                       link->psr_settings.psr_feature_enabled = false;
+                       link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
+
+                       continue;
+               }
+
                aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
                if (!aconnector)
                        goto fail;
@@ -4500,8 +4568,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                        goto fail;
                }
 
-               link = dc_get_link_at_index(dm->dc, i);
-
                if (!dc_link_detect_connection_type(link, &new_connection_type))
                        DRM_ERROR("KMS: Failed to detect connector\n");
 
@@ -5106,7 +5172,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
         * Always set input transfer function, since plane state is refreshed
         * every time.
         */
-       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
+       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state,
+                                               plane_state,
+                                               dc_plane_state);
        if (ret)
                return ret;
 
@@ -5182,6 +5250,9 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
        if (plane->type == DRM_PLANE_TYPE_CURSOR)
                return;
 
+       if (new_plane_state->rotation != DRM_MODE_ROTATE_0)
+               goto ffu;
+
        num_clips = drm_plane_get_damage_clips_count(new_plane_state);
        clips = drm_plane_get_damage_clips(new_plane_state);
 
@@ -5508,10 +5579,13 @@ static void fill_stream_properties_from_drm_display_mode(
 {
        struct dc_crtc_timing *timing_out = &stream->timing;
        const struct drm_display_info *info = &connector->display_info;
-       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+       struct amdgpu_dm_connector *aconnector = NULL;
        struct hdmi_vendor_infoframe hv_frame;
        struct hdmi_avi_infoframe avi_frame;
 
+       if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+               aconnector = to_amdgpu_dm_connector(connector);
+
        memset(&hv_frame, 0, sizeof(hv_frame));
        memset(&avi_frame, 0, sizeof(avi_frame));
 
@@ -5524,6 +5598,7 @@ static void fill_stream_properties_from_drm_display_mode(
                        && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
                timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
        else if (drm_mode_is_420_also(info, mode_in)
+                       && aconnector
                        && aconnector->force_yuv420_output)
                timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
        else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)
@@ -5559,7 +5634,7 @@ static void fill_stream_properties_from_drm_display_mode(
                timing_out->hdmi_vic = hv_frame.vic;
        }
 
-       if (is_freesync_video_mode(mode_in, aconnector)) {
+       if (aconnector && is_freesync_video_mode(mode_in, aconnector)) {
                timing_out->h_addressable = mode_in->hdisplay;
                timing_out->h_total = mode_in->htotal;
                timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start;
@@ -5680,13 +5755,13 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
 }
 
 static struct dc_sink *
-create_fake_sink(struct amdgpu_dm_connector *aconnector)
+create_fake_sink(struct dc_link *link)
 {
        struct dc_sink_init_data sink_init_data = { 0 };
        struct dc_sink *sink = NULL;
 
-       sink_init_data.link = aconnector->dc_link;
-       sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
+       sink_init_data.link = link;
+       sink_init_data.sink_signal = link->connector_signal;
 
        sink = dc_sink_create(&sink_init_data);
        if (!sink) {
@@ -6036,14 +6111,14 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
 }
 
 static struct dc_stream_state *
-create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+create_stream_for_sink(struct drm_connector *connector,
                       const struct drm_display_mode *drm_mode,
                       const struct dm_connector_state *dm_state,
                       const struct dc_stream_state *old_stream,
                       int requested_bpc)
 {
+       struct amdgpu_dm_connector *aconnector = NULL;
        struct drm_display_mode *preferred_mode = NULL;
-       struct drm_connector *drm_connector;
        const struct drm_connector_state *con_state = &dm_state->base;
        struct dc_stream_state *stream = NULL;
        struct drm_display_mode mode;
@@ -6057,22 +6132,35 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
        struct dsc_dec_dpcd_caps dsc_caps;
 
+       struct dc_link *link = NULL;
        struct dc_sink *sink = NULL;
 
        drm_mode_init(&mode, drm_mode);
        memset(&saved_mode, 0, sizeof(saved_mode));
 
-       if (aconnector == NULL) {
-               DRM_ERROR("aconnector is NULL!\n");
+       if (connector == NULL) {
+               DRM_ERROR("connector is NULL!\n");
                return stream;
        }
 
-       drm_connector = &aconnector->base;
+       if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) {
+               aconnector = NULL;
+               aconnector = to_amdgpu_dm_connector(connector);
+               link = aconnector->dc_link;
+       } else {
+               struct drm_writeback_connector *wbcon = NULL;
+               struct amdgpu_dm_wb_connector *dm_wbcon = NULL;
+
+               wbcon = drm_connector_to_writeback(connector);
+               dm_wbcon = to_amdgpu_dm_wb_connector(wbcon);
+               link = dm_wbcon->link;
+       }
 
-       if (!aconnector->dc_sink) {
-               sink = create_fake_sink(aconnector);
+       if (!aconnector || !aconnector->dc_sink) {
+               sink = create_fake_sink(link);
                if (!sink)
                        return stream;
+
        } else {
                sink = aconnector->dc_sink;
                dc_sink_retain(sink);
@@ -6085,12 +6173,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                goto finish;
        }
 
+       /* We leave this NULL for writeback connectors */
        stream->dm_stream_context = aconnector;
 
        stream->timing.flags.LTE_340MCSC_SCRAMBLE =
-               drm_connector->display_info.hdmi.scdc.scrambling.low_rates;
+               connector->display_info.hdmi.scdc.scrambling.low_rates;
 
-       list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
+       list_for_each_entry(preferred_mode, &connector->modes, head) {
                /* Search for preferred mode */
                if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
                        native_mode_found = true;
@@ -6099,7 +6188,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        }
        if (!native_mode_found)
                preferred_mode = list_first_entry_or_null(
-                               &aconnector->base.modes,
+                               &connector->modes,
                                struct drm_display_mode,
                                head);
 
@@ -6113,7 +6202,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                 * and the modelist may not be filled in time.
                 */
                DRM_DEBUG_DRIVER("No preferred mode found\n");
-       } else {
+       } else if (aconnector) {
                recalculate_timing = is_freesync_video_mode(&mode, aconnector);
                if (recalculate_timing) {
                        freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
@@ -6136,13 +6225,17 @@ 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,
+                       stream, &mode, connector, con_state, NULL,
                        requested_bpc);
        else
                fill_stream_properties_from_drm_display_mode(
-                       stream, &mode, &aconnector->base, con_state, old_stream,
+                       stream, &mode, connector, con_state, old_stream,
                        requested_bpc);
 
+       /* The rest isn't needed for writeback connectors */
+       if (!aconnector)
+               goto finish;
+
        if (aconnector->timing_changed) {
                drm_dbg(aconnector->base.dev,
                        "overriding timing for automated test, bpc %d, changing to %d\n",
@@ -6160,7 +6253,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 
        fill_audio_info(
                &stream->audio_info,
-               drm_connector,
+               connector,
                sink);
 
        update_stream_signal(stream, sink);
@@ -6267,7 +6360,7 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
                dm_new_state->underscan_enable = val;
                ret = 0;
        } else if (property == adev->mode_info.abm_level_property) {
-               dm_new_state->abm_level = val;
+               dm_new_state->abm_level = val ?: ABM_LEVEL_IMMEDIATE_DISABLE;
                ret = 0;
        }
 
@@ -6312,7 +6405,8 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
                *val = dm_state->underscan_enable;
                ret = 0;
        } else if (property == adev->mode_info.abm_level_property) {
-               *val = dm_state->abm_level;
+               *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
+                       dm_state->abm_level : 0;
                ret = 0;
        }
 
@@ -6385,7 +6479,8 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
                state->pbn = 0;
 
                if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-                       state->abm_level = amdgpu_dm_abm_level;
+                       state->abm_level = amdgpu_dm_abm_level ?:
+                               ABM_LEVEL_IMMEDIATE_DISABLE;
 
                __drm_atomic_helper_connector_reset(connector, &state->base);
        }
@@ -6626,7 +6721,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        enum dc_status dc_result = DC_OK;
 
        do {
-               stream = create_stream_for_sink(aconnector, drm_mode,
+               stream = create_stream_for_sink(connector, drm_mode,
                                                dm_state, old_stream,
                                                requested_bpc);
                if (stream == NULL) {
@@ -6634,6 +6729,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                        break;
                }
 
+               if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       return stream;
+
                dc_result = dc_validate_stream(adev->dm.dc, stream);
                if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                        dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
@@ -6909,8 +7007,8 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
        if (IS_ERR(mst_state))
                return PTR_ERR(mst_state);
 
-       if (!mst_state->pbn_div)
-               mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link);
+       if (!mst_state->pbn_div.full)
+               mst_state->pbn_div.full = dfixed_const(dm_mst_get_pbn_divider(aconnector->mst_root->dc_link));
 
        if (!state->duplicated) {
                int max_bpc = conn_state->max_requested_bpc;
@@ -6922,7 +7020,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
                                                                    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);
+               dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4);
        }
 
        dm_new_connector_state->vcpi_slots =
@@ -6954,6 +7052,9 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
 
        for_each_new_connector_in_state(state, connector, new_con_state, i) {
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
 
                if (!aconnector->mst_output_port)
@@ -7559,6 +7660,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
        struct dc_link *link = dc_get_link_at_index(dc, link_index);
        struct amdgpu_i2c_adapter *i2c;
 
+       /* Not needed for writeback connector */
        link->priv = aconnector;
 
 
@@ -8169,6 +8271,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
                        bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func;
                        bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
+                       bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult;
+                       bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func;
+                       bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func;
+                       bundle->surface_updates[planes_count].blend_tf = dc_plane->blend_tf;
                }
 
                amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
@@ -8380,6 +8486,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                &acrtc_state->stream->csc_color_matrix;
                        bundle->stream_update.out_transfer_func =
                                acrtc_state->stream->out_transfer_func;
+                       bundle->stream_update.lut3d_func =
+                               (struct dc_3dlut *) acrtc_state->stream->lut3d_func;
+                       bundle->stream_update.func_shaper =
+                               (struct dc_transfer_func *) acrtc_state->stream->func_shaper;
                }
 
                acrtc_state->stream->abm_level = acrtc_state->abm_level;
@@ -8513,6 +8623,9 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev,
                if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
                        continue;
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
 notify:
                aconnector = to_amdgpu_dm_connector(connector);
 
@@ -8546,6 +8659,9 @@ notify:
                if (!status)
                        continue;
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
 
                mutex_lock(&adev->dm.audio_lock);
@@ -8571,6 +8687,12 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat
        stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state);
 }
 
+static void dm_clear_writeback(struct amdgpu_display_manager *dm,
+                             struct dm_crtc_state *crtc_state)
+{
+       dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
+}
+
 static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
                                        struct dc_state *dc_state)
 {
@@ -8580,9 +8702,38 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
+       struct drm_connector_state *old_con_state;
+       struct drm_connector *connector;
        bool mode_set_reset_required = false;
        u32 i;
 
+       /* Disable writeback */
+       for_each_old_connector_in_state(state, connector, old_con_state, i) {
+               struct dm_connector_state *dm_old_con_state;
+               struct amdgpu_crtc *acrtc;
+
+               if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
+               old_crtc_state = NULL;
+
+               dm_old_con_state = to_dm_connector_state(old_con_state);
+               if (!dm_old_con_state->base.crtc)
+                       continue;
+
+               acrtc = to_amdgpu_crtc(dm_old_con_state->base.crtc);
+               if (acrtc)
+                       old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
+
+               if (!acrtc->wb_enabled)
+                       continue;
+
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+               dm_clear_writeback(dm, dm_old_crtc_state);
+               acrtc->wb_enabled = false;
+       }
+
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
                                      new_crtc_state, i) {
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
@@ -8719,6 +8870,105 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
        }
 }
 
+static void dm_set_writeback(struct amdgpu_display_manager *dm,
+                             struct dm_crtc_state *crtc_state,
+                             struct drm_connector *connector,
+                             struct drm_connector_state *new_con_state)
+{
+       struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector);
+       struct amdgpu_device *adev = dm->adev;
+       struct amdgpu_crtc *acrtc;
+       struct dc_writeback_info *wb_info;
+       struct pipe_ctx *pipe = NULL;
+       struct amdgpu_framebuffer *afb;
+       int i = 0;
+
+       wb_info = kzalloc(sizeof(*wb_info), GFP_KERNEL);
+       if (!wb_info) {
+               DRM_ERROR("Failed to allocate wb_info\n");
+               return;
+       }
+
+       acrtc = to_amdgpu_crtc(wb_conn->encoder.crtc);
+       if (!acrtc) {
+               DRM_ERROR("no amdgpu_crtc found\n");
+               kfree(wb_info);
+               return;
+       }
+
+       afb = to_amdgpu_framebuffer(new_con_state->writeback_job->fb);
+       if (!afb) {
+               DRM_ERROR("No amdgpu_framebuffer found\n");
+               kfree(wb_info);
+               return;
+       }
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (dm->dc->current_state->res_ctx.pipe_ctx[i].stream == crtc_state->stream) {
+                       pipe = &dm->dc->current_state->res_ctx.pipe_ctx[i];
+                       break;
+               }
+       }
+
+       /* fill in wb_info */
+       wb_info->wb_enabled = true;
+
+       wb_info->dwb_pipe_inst = 0;
+       wb_info->dwb_params.dwbscl_black_color = 0;
+       wb_info->dwb_params.hdr_mult = 0x1F000;
+       wb_info->dwb_params.csc_params.gamut_adjust_type = CM_GAMUT_ADJUST_TYPE_BYPASS;
+       wb_info->dwb_params.csc_params.gamut_coef_format = CM_GAMUT_REMAP_COEF_FORMAT_S2_13;
+       wb_info->dwb_params.output_depth = DWB_OUTPUT_PIXEL_DEPTH_10BPC;
+       wb_info->dwb_params.cnv_params.cnv_out_bpc = DWB_CNV_OUT_BPC_10BPC;
+
+       /* width & height from crtc */
+       wb_info->dwb_params.cnv_params.src_width = acrtc->base.mode.crtc_hdisplay;
+       wb_info->dwb_params.cnv_params.src_height = acrtc->base.mode.crtc_vdisplay;
+       wb_info->dwb_params.dest_width = acrtc->base.mode.crtc_hdisplay;
+       wb_info->dwb_params.dest_height = acrtc->base.mode.crtc_vdisplay;
+
+       wb_info->dwb_params.cnv_params.crop_en = false;
+       wb_info->dwb_params.stereo_params.stereo_enabled = false;
+
+       wb_info->dwb_params.cnv_params.out_max_pix_val = 0x3ff; // 10 bits
+       wb_info->dwb_params.cnv_params.out_min_pix_val = 0;
+       wb_info->dwb_params.cnv_params.fc_out_format = DWB_OUT_FORMAT_32BPP_ARGB;
+       wb_info->dwb_params.cnv_params.out_denorm_mode = DWB_OUT_DENORM_BYPASS;
+
+       wb_info->dwb_params.out_format = dwb_scaler_mode_bypass444;
+
+       wb_info->dwb_params.capture_rate = dwb_capture_rate_0;
+
+       wb_info->dwb_params.scaler_taps.h_taps = 4;
+       wb_info->dwb_params.scaler_taps.v_taps = 4;
+       wb_info->dwb_params.scaler_taps.h_taps_c = 2;
+       wb_info->dwb_params.scaler_taps.v_taps_c = 2;
+       wb_info->dwb_params.subsample_position = DWB_INTERSTITIAL_SUBSAMPLING;
+
+       wb_info->mcif_buf_params.luma_pitch = afb->base.pitches[0];
+       wb_info->mcif_buf_params.chroma_pitch = afb->base.pitches[1];
+
+       for (i = 0; i < DWB_MCIF_BUF_COUNT; i++) {
+               wb_info->mcif_buf_params.luma_address[i] = afb->address;
+               wb_info->mcif_buf_params.chroma_address[i] = 0;
+       }
+
+       wb_info->mcif_buf_params.p_vmid = 1;
+       if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) {
+               wb_info->mcif_warmup_params.start_address.quad_part = afb->address;
+               wb_info->mcif_warmup_params.region_size =
+                       wb_info->mcif_buf_params.luma_pitch * wb_info->dwb_params.dest_height;
+       }
+       wb_info->mcif_warmup_params.p_vmid = 1;
+       wb_info->writeback_source_plane = pipe->plane_state;
+
+       dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info);
+
+       acrtc->wb_pending = true;
+       acrtc->wb_conn = wb_conn;
+       drm_writeback_queue_job(wb_conn, new_con_state);
+}
+
 /**
  * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
  * @state: The atomic state to commit
@@ -8769,7 +9019,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
        for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
                struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
-               struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+               struct amdgpu_dm_connector *aconnector;
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
+               aconnector = to_amdgpu_dm_connector(connector);
 
                if (!adev->dm.hdcp_workqueue)
                        continue;
@@ -9046,6 +9301,31 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                        amdgpu_dm_commit_planes(state, dev, dm, crtc, wait_for_vblank);
        }
 
+       /* Enable writeback */
+       for_each_new_connector_in_state(state, connector, new_con_state, i) {
+               struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
+
+               if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
+               if (!new_con_state->writeback_job)
+                       continue;
+
+               new_crtc_state = NULL;
+
+               if (acrtc)
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
+
+               if (acrtc->wb_enabled)
+                       continue;
+
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               dm_set_writeback(dm, dm_new_crtc_state, connector, new_con_state);
+               acrtc->wb_enabled = true;
+       }
+
        /* Update audio instances for each connector. */
        amdgpu_dm_commit_audio(dev, state);
 
@@ -9163,10 +9443,15 @@ out:
 void dm_restore_drm_connector_state(struct drm_device *dev,
                                    struct drm_connector *connector)
 {
-       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+       struct amdgpu_dm_connector *aconnector;
        struct amdgpu_crtc *disconnected_acrtc;
        struct dm_crtc_state *acrtc_state;
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+               return;
+
+       aconnector = to_amdgpu_dm_connector(connector);
+
        if (!aconnector->dc_sink || !connector->state || !connector->encoder)
                return;
 
@@ -9243,12 +9528,16 @@ static void get_freesync_config_for_crtc(
        struct dm_connector_state *new_con_state)
 {
        struct mod_freesync_config config = {0};
-       struct amdgpu_dm_connector *aconnector =
-                       to_amdgpu_dm_connector(new_con_state->base.connector);
+       struct amdgpu_dm_connector *aconnector;
        struct drm_display_mode *mode = &new_crtc_state->base.mode;
        int vrefresh = drm_mode_vrefresh(mode);
        bool fs_vid_mode = false;
 
+       if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+               return;
+
+       aconnector = to_amdgpu_dm_connector(new_con_state->base.connector);
+
        new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
                                        vrefresh >= aconnector->min_vfreq &&
                                        vrefresh <= aconnector->max_vfreq;
@@ -9348,6 +9637,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
         * update changed items
         */
        struct amdgpu_crtc *acrtc = NULL;
+       struct drm_connector *connector = NULL;
        struct amdgpu_dm_connector *aconnector = NULL;
        struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL;
        struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL;
@@ -9357,15 +9647,17 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
        dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
        dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
        acrtc = to_amdgpu_crtc(crtc);
-       aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
+       connector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
+       if (connector)
+               aconnector = to_amdgpu_dm_connector(connector);
 
        /* TODO This hack should go away */
-       if (aconnector && enable) {
+       if (connector && enable) {
                /* Make sure fake sink is created in plug-in scenario */
                drm_new_conn_state = drm_atomic_get_new_connector_state(state,
-                                                           &aconnector->base);
+                                                                       connector);
                drm_old_conn_state = drm_atomic_get_old_connector_state(state,
-                                                           &aconnector->base);
+                                                                       connector);
 
                if (IS_ERR(drm_new_conn_state)) {
                        ret = PTR_ERR_OR_ZERO(drm_new_conn_state);
@@ -9512,7 +9804,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                 * added MST connectors not found in existing crtc_state in the chained mode
                 * TODO: need to dig out the root cause of that
                 */
-               if (!aconnector)
+               if (!connector)
                        goto skip_modeset;
 
                if (modereset_required(new_crtc_state))
@@ -9555,7 +9847,7 @@ skip_modeset:
         * We want to do dc stream updates that do not require a
         * full modeset below.
         */
-       if (!(enable && aconnector && new_crtc_state->active))
+       if (!(enable && connector && new_crtc_state->active))
                return 0;
        /*
         * Given above conditions, the dc state cannot be NULL because:
@@ -9581,6 +9873,7 @@ skip_modeset:
         * when a modeset is needed, to ensure it gets reprogrammed.
         */
        if (dm_new_crtc_state->base.color_mgmt_changed ||
+           dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf ||
            drm_atomic_crtc_needs_modeset(new_crtc_state)) {
                ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
                if (ret)
@@ -9614,7 +9907,8 @@ static bool should_reset_plane(struct drm_atomic_state *state,
         * TODO: Remove this hack for all asics once it proves that the
         * fast updates works fine on DCN3.2+.
         */
-       if (adev->ip_versions[DCE_HWIP][0] < IP_VERSION(3, 2, 0) && state->allow_modeset)
+       if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 2, 0) &&
+           state->allow_modeset)
                return true;
 
        /* Exit early if we know that we're adding or removing the plane. */
@@ -9648,6 +9942,10 @@ static bool should_reset_plane(struct drm_atomic_state *state,
         */
        for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) {
                struct amdgpu_framebuffer *old_afb, *new_afb;
+               struct dm_plane_state *dm_new_other_state, *dm_old_other_state;
+
+               dm_new_other_state = to_dm_plane_state(new_other_state);
+               dm_old_other_state = to_dm_plane_state(old_other_state);
 
                if (other->type == DRM_PLANE_TYPE_CURSOR)
                        continue;
@@ -9684,6 +9982,18 @@ static bool should_reset_plane(struct drm_atomic_state *state,
                    old_other_state->color_encoding != new_other_state->color_encoding)
                        return true;
 
+               /* HDR/Transfer Function changes. */
+               if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf ||
+                   dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut ||
+                   dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult ||
+                   dm_old_other_state->ctm != dm_new_other_state->ctm ||
+                   dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut ||
+                   dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf ||
+                   dm_old_other_state->lut3d != dm_new_other_state->lut3d ||
+                   dm_old_other_state->blend_lut != dm_new_other_state->blend_lut ||
+                   dm_old_other_state->blend_tf != dm_new_other_state->blend_tf)
+                       return true;
+
                /* Framebuffer checks fall at the end. */
                if (!old_other_state->fb || !new_other_state->fb)
                        continue;
@@ -10078,6 +10388,9 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
                if (conn_state->crtc != crtc)
                        continue;
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
                aconnector = to_amdgpu_dm_connector(connector);
                if (!aconnector->mst_output_port || !aconnector->mst_root)
                        aconnector = NULL;
@@ -10788,8 +11101,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
        struct dm_connector_state *dm_con_state = NULL;
        struct dc_sink *sink;
 
-       struct drm_device *dev = connector->dev;
-       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct amdgpu_device *adev = drm_to_adev(connector->dev);
        struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
        bool freesync_capable = false;
        enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
This page took 0.073017 seconds and 4 git commands to generate.