diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
12 files changed, 287 insertions, 93 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7c51d8d7e73c..47749ccc9c43 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -153,12 +153,6 @@ MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB); #define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); -/* Number of bytes in PSP header for firmware. */ -#define PSP_HEADER_BYTES 0x100 - -/* Number of bytes in PSP footer for firmware. */ -#define PSP_FOOTER_BYTES 0x100 - /** * DOC: overview * @@ -1144,7 +1138,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, mutex_unlock(&adev->dm.audio_lock); - DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); return ret; } @@ -1238,7 +1232,7 @@ static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) struct drm_audio_component *acomp = adev->dm.audio_component; if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { - DRM_DEBUG_KMS("Notify ELD: %d\n", pin); + drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin); acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, pin, -1); @@ -1299,15 +1293,14 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) fw_inst_const = dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES; + PSP_HEADER_BYTES_256; fw_bss_data = dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + le32_to_cpu(hdr->inst_const_bytes); /* Copy firmware and bios info into FB memory. */ - fw_inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; + fw_inst_const_size = adev->dm.fw_inst_size; fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes); @@ -1344,8 +1337,8 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) /* Initialize hardware. */ memset(&hw_params, 0, sizeof(hw_params)); - hw_params.fb_base = adev->gmc.fb_start; - hw_params.fb_offset = adev->vm_manager.vram_base_offset; + hw_params.soc_fb_info.fb_base = adev->gmc.fb_start; + hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset; /* backdoor load firmware and trigger dmub running */ if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) @@ -2106,7 +2099,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) drm_err(adev_to_drm(adev), "failed to initialize freesync_module.\n"); } else - drm_dbg_driver(adev_to_drm(adev), "amdgpu: freesync_module init done %p.\n", + drm_dbg_driver(adev_to_drm(adev), "freesync_module init done %p.\n", adev->dm.freesync_module); amdgpu_dm_init_color_mod(); @@ -2128,7 +2121,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (!adev->dm.hdcp_workqueue) drm_err(adev_to_drm(adev), "failed to initialize hdcp_workqueue.\n"); else - drm_dbg_driver(adev_to_drm(adev), "amdgpu: hdcp_workqueue init done %p.\n", adev->dm.hdcp_workqueue); + drm_dbg_driver(adev_to_drm(adev), + "hdcp_workqueue init done %p.\n", + adev->dm.hdcp_workqueue); dc_init_callbacks(adev->dm.dc, &init_params); } @@ -2383,7 +2378,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) } if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { - DRM_DEBUG_KMS("dm: DMCU firmware not supported on direct or SMU loading\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not supported on direct or SMU loading\n"); return 0; } @@ -2391,7 +2386,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) "%s", fw_name_dmcu); if (r == -ENODEV) { /* DMCU firmware is not necessary, so don't raise a fuss if it's missing */ - DRM_DEBUG_KMS("dm: DMCU firmware not found\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not found\n"); adev->dm.fw_dmcu = NULL; return 0; } @@ -2415,7 +2410,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) adev->dm.dmcu_fw_version = le32_to_cpu(hdr->header.ucode_version); - DRM_DEBUG_KMS("PSP loading DMCU firmware\n"); + drm_dbg_kms(adev_to_drm(adev), "PSP loading DMCU firmware\n"); return 0; } @@ -2438,9 +2433,11 @@ static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, static int dm_dmub_sw_init(struct amdgpu_device *adev) { struct dmub_srv_create_params create_params; + struct dmub_srv_fw_meta_info_params fw_meta_info_params; struct dmub_srv_region_params region_params; struct dmub_srv_region_info region_info; struct dmub_srv_memory_params memory_params; + struct dmub_fw_meta_info fw_info; struct dmub_srv_fb_info *fb_info; struct dmub_srv *dmub_srv; const struct dmcub_firmware_header_v1_0 *hdr; @@ -2548,22 +2545,37 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) return -EINVAL; } + /* Extract the FW meta info. */ + memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params)); + + fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - + PSP_HEADER_BYTES_256; + fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + PSP_HEADER_BYTES_256; + fw_meta_info_params.fw_bss_data = region_params.bss_data_size ? adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + le32_to_cpu(hdr->inst_const_bytes) : NULL; + fw_meta_info_params.custom_psp_footer_size = 0; + + status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info); + if (status != DMUB_STATUS_OK) { + /* Skip returning early, just log the error. */ + drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status); + // return -EINVAL; + } + /* Calculate the size of all the regions for the DMUB service. */ memset(®ion_params, 0, sizeof(region_params)); - region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; - region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + region_params.inst_const_size = fw_meta_info_params.inst_const_size; + region_params.bss_data_size = fw_meta_info_params.bss_data_size; region_params.vbios_size = adev->bios_size; - region_params.fw_bss_data = region_params.bss_data_size ? - adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - le32_to_cpu(hdr->inst_const_bytes) : NULL; - region_params.fw_inst_const = - adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES; + region_params.fw_bss_data = fw_meta_info_params.fw_bss_data; + region_params.fw_inst_const = fw_meta_info_params.fw_inst_const; region_params.window_memory_type = window_memory_type; + region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL; status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, ®ion_info); @@ -2610,6 +2622,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) } adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); + adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size; return 0; } @@ -4149,7 +4162,7 @@ static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_ offload_work->adev = adev; queue_work(offload_wq->wq, &offload_work->work); - DRM_DEBUG_KMS("queue work to handle hpd_rx offload work"); + drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work"); } static void handle_hpd_rx_irq(void *param) @@ -4978,7 +4991,7 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, caps->min_input_signal < 0 || spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || spread < AMDGPU_DM_MIN_SPREAD) { - DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, max=%d\n", + drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n", caps->min_input_signal, caps->max_input_signal); caps->caps_valid = false; } @@ -5271,6 +5284,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; int min, max; + int real_brightness; + int init_brightness; if (aconnector->bl_idx == -1) return; @@ -5295,6 +5310,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; + init_brightness = props.brightness; + if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { drm_info(drm, "Using custom brightness curve\n"); props.scale = BACKLIGHT_SCALE_NON_LINEAR; @@ -5313,8 +5330,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { drm_err(drm, "DM: Backlight registration failed!\n"); dm->backlight_dev[aconnector->bl_idx] = NULL; - } else + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } } static int initialize_plane(struct amdgpu_display_manager *dm, @@ -5507,7 +5536,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } break; default: - DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", + drm_dbg_kms(adev_to_drm(adev), "Unsupported DCN IP version for outbox: 0x%X\n", amdgpu_ip_version(adev, DCE_HWIP, 0)); } @@ -5631,7 +5660,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (psr_feature_enabled) { amdgpu_dm_set_psr_caps(link); - drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + aconnector->base.name, link->psr_settings.psr_feature_enabled, link->psr_settings.psr_version, link->dpcd_caps.psr_info.psr_version, @@ -6409,7 +6439,8 @@ ffu: &flip_addrs->dirty_rect_count, true); } -static void update_stream_scaling_settings(const struct drm_display_mode *mode, +static void update_stream_scaling_settings(struct drm_device *dev, + const struct drm_display_mode *mode, const struct dm_connector_state *dm_state, struct dc_stream_state *stream) { @@ -6459,8 +6490,8 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, stream->src = src; stream->dst = dst; - DRM_DEBUG_KMS("Destination Rectangle x:%d y:%d width:%d height:%d\n", - dst.x, dst.y, dst.width, dst.height); + drm_dbg_kms(dev, "Destination Rectangle x:%d y:%d width:%d height:%d\n", + dst.x, dst.y, dst.width, dst.height); } @@ -7348,7 +7379,7 @@ create_stream_for_sink(struct drm_connector *connector, apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); #endif - update_stream_scaling_settings(&mode, dm_state, stream); + update_stream_scaling_settings(dev, &mode, dm_state, stream); fill_audio_info( &stream->audio_info, @@ -7422,7 +7453,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) * * Only allow to poll such a connector again when forcing. */ - if (!force && link->local_sink && link->type == dc_connection_dac_load) + if (!force && link->local_sink && link->type == dc_connection_analog_load) return connector->status; mutex_lock(&aconnector->hpd_lock); @@ -7742,10 +7773,12 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector) drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr); /* Cancel and flush any pending HDMI HPD debounce work */ - cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work); - if (aconnector->hdmi_prev_sink) { - dc_sink_release(aconnector->hdmi_prev_sink); - aconnector->hdmi_prev_sink = NULL; + if (aconnector->hdmi_hpd_debounce_delay_ms) { + cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work); + if (aconnector->hdmi_prev_sink) { + dc_sink_release(aconnector->hdmi_prev_sink); + aconnector->hdmi_prev_sink = NULL; + } } if (aconnector->bl_idx != -1) { @@ -8083,7 +8116,7 @@ create_validate_stream_for_sink(struct drm_connector *connector, dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); if (dc_result != DC_OK) { - DRM_DEBUG_KMS("Pruned mode %d x %d (clk %d) %s %s -- %s\n", + drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n", drm_mode->hdisplay, drm_mode->vdisplay, drm_mode->clock, @@ -8435,7 +8468,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, dm_new_connector_state->pbn); if (dm_new_connector_state->vcpi_slots < 0) { - DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); return dm_new_connector_state->vcpi_slots; } return 0; @@ -8935,9 +8968,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, mutex_init(&aconnector->hpd_lock); mutex_init(&aconnector->handle_mst_msg_ready); - aconnector->hdmi_hpd_debounce_delay_ms = AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS; - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); - aconnector->hdmi_prev_sink = NULL; + /* + * If HDMI HPD debounce delay is set, use the minimum between selected + * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS + */ + if (amdgpu_hdmi_hpd_debounce_delay_ms) { + aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, + AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); + INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); + aconnector->hdmi_prev_sink = NULL; + } else { + aconnector->hdmi_hpd_debounce_delay_ms = 0; + } /* * configure support HPD hot plug connector_>polled default value is 0 @@ -9621,7 +9663,7 @@ static void update_freesync_state_on_stream( new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params); if (new_crtc_state->freesync_vrr_info_changed) - DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d", + drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d", new_crtc_state->base.crtc->base.id, (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); @@ -10887,7 +10929,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) stream_update.stream = dm_new_crtc_state->stream; if (scaling_changed) { - update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, + update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode, dm_new_con_state, dm_new_crtc_state->stream); stream_update.src = dm_new_crtc_state->stream->src; @@ -11567,7 +11609,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dc_stream_retain(new_stream); - DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n", + drm_dbg_atomic(adev_to_drm(adev), "Enabling DRM crtc: %d\n", crtc->base.id); if (dc_state_add_stream( @@ -11606,7 +11648,7 @@ skip_modeset: /* Scaling or underscan settings */ if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) || drm_atomic_crtc_needs_modeset(new_crtc_state)) - update_stream_scaling_settings( + update_stream_scaling_settings(adev_to_drm(adev), &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); /* ABM settings */ @@ -11797,14 +11839,14 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, if (fb->width > new_acrtc->max_cursor_width || fb->height > new_acrtc->max_cursor_height) { - DRM_DEBUG_ATOMIC("Bad cursor FB size %dx%d\n", + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size %dx%d\n", new_plane_state->fb->width, new_plane_state->fb->height); return -EINVAL; } if (new_plane_state->src_w != fb->width << 16 || new_plane_state->src_h != fb->height << 16) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(adev_to_drm(adev), "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11812,7 +11854,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, pitch = fb->pitches[0] / fb->format->cpp[0]; if (fb->width != pitch) { - DRM_DEBUG_ATOMIC("Cursor FB width %d doesn't match pitch %d", + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d doesn't match pitch %d", fb->width, pitch); return -EINVAL; } @@ -11824,7 +11866,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, /* FB pitch is supported by cursor plane */ break; default: - DRM_DEBUG_ATOMIC("Bad cursor FB pitch %d px\n", pitch); + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch %d px\n", pitch); return -EINVAL; } @@ -11832,7 +11874,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, * check tiling flags when the FB doesn't have a modifier. */ if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) { - if (adev->family >= AMDGPU_FAMILY_GC_12_0_0) { + if (adev->family == AMDGPU_FAMILY_GC_12_0_0) { linear = AMDGPU_TILING_GET(afb->tiling_flags, GFX12_SWIZZLE_MODE) == 0; } else if (adev->family >= AMDGPU_FAMILY_AI) { linear = AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0; @@ -11842,7 +11884,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0; } if (!linear) { - DRM_DEBUG_ATOMIC("Cursor FB not linear"); + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB not linear"); return -EINVAL; } } @@ -11869,7 +11911,7 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, new_acrtc = to_amdgpu_crtc(new_plane_crtc); if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(new_plane_crtc->dev, "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11968,7 +12010,7 @@ static int dm_update_plane_state(struct dc *dc, if (!dm_old_crtc_state->stream) return 0; - DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(old_plane_crtc->dev, "Disabling DRM plane: %d on DRM crtc %d\n", plane->base.id, old_plane_crtc->base.id); ret = dm_atomic_get_state(state, &dm_state); @@ -12021,7 +12063,7 @@ static int dm_update_plane_state(struct dc *dc, goto out; } - DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(new_plane_crtc->dev, "Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); ret = fill_dc_plane_attributes( @@ -13111,9 +13153,24 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, if (ieeeId == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID && amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) { + u8 panel_type; vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false; vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3; - DRM_DEBUG_KMS("Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); + drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); + panel_type = (amd_vsdb->color_space_eotf_support & AMD_VDSB_VERSION_3_PANEL_TYPE_MASK) >> AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT; + switch (panel_type) { + case AMD_VSDB_PANEL_TYPE_OLED: + aconnector->dc_link->panel_type = PANEL_TYPE_OLED; + break; + case AMD_VSDB_PANEL_TYPE_MINILED: + aconnector->dc_link->panel_type = PANEL_TYPE_MINILED; + break; + default: + aconnector->dc_link->panel_type = PANEL_TYPE_NONE; + break; + } + drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", + aconnector->dc_link->panel_type); return true; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index bd0403005f37..800813671748 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -55,11 +55,23 @@ #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 +#define AMD_VDSB_VERSION_3_PANEL_TYPE_MASK 0xC0 +#define AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT 6 #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3 +enum amd_vsdb_panel_type { + AMD_VSDB_PANEL_TYPE_DEFAULT = 0, + AMD_VSDB_PANEL_TYPE_MINILED, + AMD_VSDB_PANEL_TYPE_OLED, + AMD_VSDB_PANEL_TYPE_RESERVED, +}; + #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) -#define AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS 1500 +/* + * Maximum HDMI HPD debounce delay in milliseconds + */ +#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000 /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" @@ -89,6 +101,8 @@ struct amd_vsdb_block { unsigned char ieee_id[3]; unsigned char version; unsigned char feature_caps; + unsigned char reserved[3]; + unsigned char color_space_eotf_support; }; struct common_irq_params { @@ -414,6 +428,13 @@ struct amdgpu_display_manager { uint32_t dmcub_fw_version; /** + * @fw_inst_size: + * + * Size of the firmware instruction buffer. + */ + uint32_t fw_inst_size; + + /** * @cgs_device: * * The Common Graphics Services device. It provides an interface for @@ -808,6 +829,7 @@ struct amdgpu_dm_connector { int sr_skip_count; bool disallow_edp_enter_psr; + bool disallow_edp_enter_replay; /* Record progress status of mst*/ uint8_t mst_status; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c index d585618b8064..a2de3bba8346 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c @@ -79,7 +79,6 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr goto cleanup; list->type = ops[i]->base.id; - list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]->base.id); i++; @@ -197,6 +196,9 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr goto cleanup; drm_colorop_set_next_property(ops[i-1], ops[i]); + + list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id); + return 0; cleanup: diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index e20aa7438066..5851f2d55dde 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -32,6 +32,7 @@ #include "dc.h" #include "amdgpu_securedisplay.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" static const char *const pipe_crc_sources[] = { "none", @@ -105,7 +106,9 @@ static void update_phy_id_mapping(struct amdgpu_device *adev) continue; if (idx >= AMDGPU_DM_MAX_CRTC) { - DRM_WARN("%s connected connectors exceed max crtc\n", __func__); + drm_warn(adev_to_drm(adev), + "%s connected connectors exceed max crtc\n", + __func__); mutex_unlock(&ddev->mode_config.mutex); return; } @@ -500,6 +503,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, { struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc_stream_state *stream_state = dm_crtc_state->stream; + struct amdgpu_dm_connector *aconnector = NULL; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; @@ -507,11 +511,22 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, if (!stream_state) return -EINVAL; + /* Get connector from stream */ + aconnector = (struct amdgpu_dm_connector *)stream_state->dm_stream_context; + mutex_lock(&adev->dm.dc_lock); - /* For PSR1, check that the panel has exited PSR */ - if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) - amdgpu_dm_psr_wait_disable(stream_state); + + if (enable) { + /* For PSR1, check that the panel has exited PSR */ + if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) + amdgpu_dm_psr_wait_disable(stream_state); + + /* Set flag to disallow enter replay when CRC source is enabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = true; + amdgpu_dm_replay_disable(stream_state); + } /* Enable or disable CRTC CRC generation */ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { @@ -534,6 +549,12 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, DYN_EXPANSION_AUTO); } + if (!enable) { + /* Clear flag to allow enter replay when CRC source is disabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = false; + } + unlock: mutex_unlock(&adev->dm.dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 697e232acebf..9fcd72d87d25 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -248,8 +248,6 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) struct vblank_control_work *vblank_work = container_of(work, struct vblank_control_work, work); struct amdgpu_display_manager *dm = vblank_work->dm; - struct amdgpu_device *adev = drm_to_adev(dm->ddev); - int r; mutex_lock(&dm->dc_lock); @@ -279,16 +277,7 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) if (dm->active_vblank_irq_count == 0) { dc_post_update_surfaces_to_stream(dm->dc); - - r = amdgpu_dpm_pause_power_profile(adev, true); - if (r) - dev_warn(adev->dev, "failed to set default power profile mode\n"); - dc_allow_idle_optimizations(dm->dc, true); - - r = amdgpu_dpm_pause_power_profile(adev, false); - if (r) - dev_warn(adev->dev, "failed to restore the power profile mode\n"); } mutex_unlock(&dm->dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index a9839485f2a2..b9ed29ec60dc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -95,7 +95,7 @@ static int parse_write_buffer_into_params(char *wr_buf, uint32_t wr_buf_size, return -EFAULT; } - /* check number of parameters. isspace could not differ space and \n */ + /* check number of parameters. isspace could not differ space and\n */ while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) { /* skip space*/ while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { @@ -2710,6 +2710,65 @@ static int ips_status_show(struct seq_file *m, void *unused) } /* + * IPS residency information from DMUB service. Read only. + * + * For time-window (segment) measurement: + * 1) echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_ips_residency_cntl + * 2) sleep <seconds> + * 3) echo 0 > /sys/kernel/debug/dri/0/amdgpu_dm_ips_residency_cntl + * 4) cat /sys/kernel/debug/dri/0/amdgpu_dm_ips_residency + */ +static int ips_residency_show(struct seq_file *m, void *unused) +{ + struct amdgpu_device *adev = m->private; + struct dc *dc = adev->dm.dc; + uint8_t panel_inst = 0; + enum ips_residency_mode mode; + struct dmub_ips_residency_info info; + + mutex_lock(&adev->dm.dc_lock); + + mode = IPS_RESIDENCY__IPS1_RCG; + if (!dc_dmub_srv_ips_query_residency_info(dc->ctx, panel_inst, &info, mode)) { + seq_printf(m, "ISP query failed\n"); + } else { + unsigned int pct, frac; + pct = info.residency_millipercent / 1000; + frac = info.residency_millipercent % 1000; + + seq_printf(m, "IPS residency: %u.%03u%% \n", pct, frac); + seq_printf(m, " entry_counter: %u\n", info.entry_counter); + seq_printf(m, " total_time_us: %llu\n", + (unsigned long long)info.total_time_us); + seq_printf(m, " total_inactive_time_us: %llu\n", + (unsigned long long)info.total_inactive_time_us); + } + mutex_unlock(&adev->dm.dc_lock); + return 0; +} + +static int ips_residency_cntl_get(void *data, u64 *val) +{ + *val = 0; + return 0; +} + +static int ips_residency_cntl_set(void *data, u64 val) +{ + struct amdgpu_device *adev = data; + struct dc *dc = adev->dm.dc; + uint8_t panel_inst = 0; + int ret = 0; + + mutex_lock(&adev->dm.dc_lock); + if (!dc_dmub_srv_ips_residency_cntl(dc->ctx, panel_inst, !!val)) + ret = -EIO; + mutex_unlock(&adev->dm.dc_lock); + + return ret; +} + +/* * Backlight at this moment. Read only. * As written to display, taking ABM and backlight lut into account. * Ranges from 0x0 to 0x10000 (= 100% PWM) @@ -3370,9 +3429,12 @@ DEFINE_DEBUGFS_ATTRIBUTE(disallow_edp_enter_psr_fops, disallow_edp_enter_psr_get, disallow_edp_enter_psr_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(ips_residency_cntl_fops, ips_residency_cntl_get, + ips_residency_cntl_set, "%llu\n"); DEFINE_SHOW_ATTRIBUTE(current_backlight); DEFINE_SHOW_ATTRIBUTE(target_backlight); DEFINE_SHOW_ATTRIBUTE(ips_status); +DEFINE_SHOW_ATTRIBUTE(ips_residency); static const struct { char *name; @@ -4271,7 +4333,14 @@ void dtn_debugfs_init(struct amdgpu_device *adev) debugfs_create_file_unsafe("amdgpu_dm_disable_hpd", 0644, root, adev, &disable_hpd_ops); - if (adev->dm.dc->caps.ips_support) + if (adev->dm.dc->caps.ips_support) { debugfs_create_file_unsafe("amdgpu_dm_ips_status", 0644, root, adev, &ips_status_fops); + + debugfs_create_file_unsafe("amdgpu_dm_ips_residency_cntl", 0644, root, adev, + &ips_residency_cntl_fops); + + debugfs_create_file_unsafe("amdgpu_dm_ips_residency", 0644, root, adev, + &ips_residency_fops); + } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 85ce558cefc5..a10401675f53 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -503,7 +503,8 @@ static bool enable_assr(void *handle, struct dc_link *link) struct ta_dtm_shared_memory *dtm_cmd; if (!psp->dtm_context.context.initialized) { - DRM_INFO("Failed to enable ASSR, DTM TA is not initialized."); + drm_info(adev_to_drm(psp->adev), + "Failed to enable ASSR, DTM TA is not initialized."); return false; } @@ -520,7 +521,8 @@ static bool enable_assr(void *handle, struct dc_link *link) psp_dtm_invoke(psp, dtm_cmd->cmd_id); if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { - DRM_INFO("Failed to enable ASSR"); + drm_info(adev_to_drm(psp->adev), + "Failed to enable ASSR"); return false; } @@ -813,7 +815,7 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, sysfs_bin_attr_init(&hdcp_work[0].attr); if (sysfs_create_bin_file(&adev->dev->kobj, &hdcp_work[0].attr)) - DRM_WARN("Failed to create device file hdcp_srm"); + drm_warn(adev_to_drm(adev), "Failed to create device file hdcp_srm\n"); return hdcp_work; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index e5e993d3ef74..1f41d6540b83 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -1121,6 +1121,12 @@ void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks) /* TODO: something */ } +void dm_helpers_dmu_timeout(struct dc_context *ctx) +{ + // TODO: + //amdgpu_device_gpu_recover(dc_context->driver-context, NULL); +} + void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us) { // TODO: diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 0a2a3f233a0e..e7b0928bd3db 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -915,13 +915,19 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) struct amdgpu_dm_connector *amdgpu_dm_connector; const struct dc_link *dc_link; - use_polling |= connector->polled != DRM_CONNECTOR_POLL_HPD; - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) continue; amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + /* + * Analog connectors may be hot-plugged unlike other connector + * types that don't support HPD. Only poll analog connectors. + */ + use_polling |= + amdgpu_dm_connector->dc_link && + dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id); + dc_link = amdgpu_dm_connector->dc_link; /* diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 8c5912b59e19..d3e62f511c8f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -278,7 +278,7 @@ static int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, if (!dcc->enable) return 0; - if (adev->family < AMDGPU_FAMILY_GC_12_0_0 && + if (adev->family != AMDGPU_FAMILY_GC_12_0_0 && format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) return -EINVAL; @@ -901,7 +901,7 @@ int amdgpu_dm_plane_fill_plane_buffer_attributes(struct amdgpu_device *adev, upper_32_bits(chroma_addr); } - if (adev->family >= AMDGPU_FAMILY_GC_12_0_0) { + if (adev->family == AMDGPU_FAMILY_GC_12_0_0) { ret = amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers(adev, afb, format, rotation, plane_size, tiling_info, dcc, @@ -1790,12 +1790,13 @@ dm_atomic_plane_get_property(struct drm_plane *plane, static int dm_plane_init_colorops(struct drm_plane *plane) { - struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES]; + struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES] = {}; struct drm_device *dev = plane->dev; struct amdgpu_device *adev = drm_to_adev(dev); struct dc *dc = adev->dm.dc; int len = 0; - int ret; + int ret = 0; + int i; if (plane->type == DRM_PLANE_TYPE_CURSOR) return 0; @@ -1806,7 +1807,7 @@ dm_plane_init_colorops(struct drm_plane *plane) if (ret) { drm_err(plane->dev, "Failed to create color pipeline for plane %d: %d\n", plane->base.id, ret); - return ret; + goto out; } len++; @@ -1814,7 +1815,11 @@ dm_plane_init_colorops(struct drm_plane *plane) drm_plane_create_color_pipeline_property(plane, pipelines, len); } - return 0; +out: + for (i = 0; i < len; i++) + kfree(pipelines[i].name); + + return ret; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index da94e3544b65..8c150b001105 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -154,14 +154,21 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) { bool replay_active = true; struct dc_link *link = NULL; + struct amdgpu_dm_connector *aconnector = NULL; if (stream == NULL) return false; + /* Check if replay is disabled by connector flag */ + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + if (!aconnector || aconnector->disallow_edp_enter_replay) { + return false; + } + link = stream->link; if (link) { - link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->dp_setup_replay(link, stream); link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total, 0); DRM_DEBUG_DRIVER("Enabling replay...\n"); link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h index b8275b397920..4e921632bc4e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h @@ -31,4 +31,12 @@ void dc_assert_fp_enabled(void); void dc_fpu_begin(const char *function_name, const int line); void dc_fpu_end(const char *function_name, const int line); +#ifndef _LINUX_FPU_COMPILATION_UNIT +#define DC_FP_START() dc_fpu_begin(__func__, __LINE__) +#define DC_FP_END() dc_fpu_end(__func__, __LINE__) +#else +#define DC_FP_START() BUILD_BUG() +#define DC_FP_END() BUILD_BUG() +#endif + #endif /* __DC_FPU_H__ */ |
