diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
11 files changed, 1852 insertions, 370 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 0f7749e9424d..2c4dbdeec46a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -34,6 +34,7 @@ #include "dc/inc/hw/dmcu.h" #include "dc/inc/hw/abm.h" #include "dc/dc_dmub_srv.h" +#include "amdgpu_dm_trace.h" #include "vid.h" #include "amdgpu.h" @@ -94,14 +95,16 @@ #define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) #define FIRMWARE_SIENNA_CICHLID_DMUB "amdgpu/sienna_cichlid_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB); #define FIRMWARE_NAVY_FLOUNDER_DMUB "amdgpu/navy_flounder_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB); -#endif #define FIRMWARE_GREEN_SARDINE_DMUB "amdgpu/green_sardine_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB); +#define FIRMWARE_VANGOGH_DMUB "amdgpu/vangogh_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); +#define FIRMWARE_DIMGREY_CAVEFISH_DMUB "amdgpu/dimgrey_cavefish_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); #define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); @@ -193,10 +196,6 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev, static int amdgpu_dm_connector_get_modes(struct drm_connector *connector); -static int amdgpu_dm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock); - static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state); static int amdgpu_dm_atomic_check(struct drm_device *dev, @@ -211,6 +210,9 @@ static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream); static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream); static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm); +static const struct drm_format_info * +amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd); + /* * dm_vblank_get_counter * @@ -882,44 +884,95 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) return 0; } -static void amdgpu_check_debugfs_connector_property_change(struct amdgpu_device *adev, - struct drm_atomic_state *state) +#if defined(CONFIG_DRM_AMD_DC_DCN) +static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config) { - struct drm_connector *connector; - struct drm_crtc *crtc; - struct amdgpu_dm_connector *amdgpu_dm_connector; - struct drm_connector_state *conn_state; - struct dm_crtc_state *acrtc_state; - struct drm_crtc_state *crtc_state; - struct dc_stream_state *stream; - struct drm_device *dev = adev_to_drm(adev); + uint64_t pt_base; + uint32_t logical_addr_low; + uint32_t logical_addr_high; + uint32_t agp_base, agp_bot, agp_top; + PHYSICAL_ADDRESS_LOC page_table_start, page_table_end, page_table_base; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; + pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); - amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - conn_state = connector->state; + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the + * workaround that increase system aperture high address (add 1) + * to get rid of the VM fault and hardware hang. + */ + logical_addr_high = max((adev->gmc.fb_end >> 18) + 0x1, adev->gmc.agp_end >> 18); + else + logical_addr_high = max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18; - if (!(conn_state && conn_state->crtc)) - continue; + agp_base = 0; + agp_bot = adev->gmc.agp_start >> 24; + agp_top = adev->gmc.agp_end >> 24; - crtc = conn_state->crtc; - acrtc_state = to_dm_crtc_state(crtc->state); - if (!(acrtc_state && acrtc_state->stream)) - continue; + page_table_start.high_part = (u32)(adev->gmc.gart_start >> 44) & 0xF; + page_table_start.low_part = (u32)(adev->gmc.gart_start >> 12); + page_table_end.high_part = (u32)(adev->gmc.gart_end >> 44) & 0xF; + page_table_end.low_part = (u32)(adev->gmc.gart_end >> 12); + page_table_base.high_part = upper_32_bits(pt_base) & 0xF; + page_table_base.low_part = lower_32_bits(pt_base); - stream = acrtc_state->stream; + pa_config->system_aperture.start_addr = (uint64_t)logical_addr_low << 18; + pa_config->system_aperture.end_addr = (uint64_t)logical_addr_high << 18; - if (amdgpu_dm_connector->dsc_settings.dsc_force_enable || - amdgpu_dm_connector->dsc_settings.dsc_num_slices_v || - amdgpu_dm_connector->dsc_settings.dsc_num_slices_h || - amdgpu_dm_connector->dsc_settings.dsc_bits_per_pixel) { - conn_state = drm_atomic_get_connector_state(state, connector); - crtc_state = drm_atomic_get_crtc_state(state, crtc); - crtc_state->mode_changed = true; - } - } + pa_config->system_aperture.agp_base = (uint64_t)agp_base << 24 ; + pa_config->system_aperture.agp_bot = (uint64_t)agp_bot << 24; + pa_config->system_aperture.agp_top = (uint64_t)agp_top << 24; + + pa_config->system_aperture.fb_base = adev->gmc.fb_start; + pa_config->system_aperture.fb_offset = adev->gmc.aper_base; + pa_config->system_aperture.fb_top = adev->gmc.fb_end; + + pa_config->gart_config.page_table_start_addr = page_table_start.quad_part << 12; + pa_config->gart_config.page_table_end_addr = page_table_end.quad_part << 12; + pa_config->gart_config.page_table_base_addr = page_table_base.quad_part; + + pa_config->is_hvm_enabled = 0; + +} +#endif + +#ifdef CONFIG_DEBUG_FS +static int create_crtc_crc_properties(struct amdgpu_display_manager *dm) +{ + dm->crc_win_x_start_property = + drm_property_create_range(adev_to_drm(dm->adev), + DRM_MODE_PROP_ATOMIC, + "AMD_CRC_WIN_X_START", 0, U16_MAX); + if (!dm->crc_win_x_start_property) + return -ENOMEM; + + dm->crc_win_y_start_property = + drm_property_create_range(adev_to_drm(dm->adev), + DRM_MODE_PROP_ATOMIC, + "AMD_CRC_WIN_Y_START", 0, U16_MAX); + if (!dm->crc_win_y_start_property) + return -ENOMEM; + + dm->crc_win_x_end_property = + drm_property_create_range(adev_to_drm(dm->adev), + DRM_MODE_PROP_ATOMIC, + "AMD_CRC_WIN_X_END", 0, U16_MAX); + if (!dm->crc_win_x_end_property) + return -ENOMEM; + + dm->crc_win_y_end_property = + drm_property_create_range(adev_to_drm(dm->adev), + DRM_MODE_PROP_ATOMIC, + "AMD_CRC_WIN_Y_END", 0, U16_MAX); + if (!dm->crc_win_y_end_property) + return -ENOMEM; + + return 0; } +#endif static int amdgpu_dm_init(struct amdgpu_device *adev) { @@ -978,6 +1031,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) init_data.flags.disable_dmcu = true; break; +#if defined(CONFIG_DRM_AMD_DC_DCN) + case CHIP_VANGOGH: + init_data.flags.gpu_vm_support = true; + break; +#endif default: break; } @@ -1030,6 +1088,17 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_hardware_init(adev->dm.dc); +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (adev->apu_flags) { + struct dc_phy_addr_space_config pa_config; + + mmhub_read_system_context(adev, &pa_config); + + // Call the DC init_memory func + dc_setup_system_context(adev->dm.dc, &pa_config); + } +#endif + adev->dm.freesync_module = mod_freesync_create(adev->dm.dc); if (!adev->dm.freesync_module) { DRM_ERROR( @@ -1052,6 +1121,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_init_callbacks(adev->dm.dc, &init_params); } #endif +#ifdef CONFIG_DEBUG_FS + if (create_crtc_crc_properties(&adev->dm)) + DRM_ERROR("amdgpu: failed to create crc property.\n"); +#endif if (amdgpu_dm_initialize_drm_device(adev)) { DRM_ERROR( "amdgpu: failed to initialize sw for display support.\n"); @@ -1073,6 +1146,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) goto error; } + DRM_DEBUG_DRIVER("KMS initialized.\n"); return 0; @@ -1169,10 +1243,10 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_RENOIR: -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: -#endif + case CHIP_DIMGREY_CAVEFISH: + case CHIP_VANGOGH: return 0; case CHIP_NAVI12: fw_name_dmcu = FIRMWARE_NAVI12_DMCU; @@ -1271,7 +1345,6 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB; break; -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: dmub_asic = DMUB_ASIC_DCN30; fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; @@ -1280,7 +1353,14 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) dmub_asic = DMUB_ASIC_DCN30; fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB; break; -#endif + case CHIP_VANGOGH: + dmub_asic = DMUB_ASIC_DCN301; + fw_name_dmub = FIRMWARE_VANGOGH_DMUB; + break; + case CHIP_DIMGREY_CAVEFISH: + dmub_asic = DMUB_ASIC_DCN302; + fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB; + break; default: /* ASIC doesn't support DMUB. */ @@ -1902,6 +1982,33 @@ cleanup: return; } +static void dm_set_dpms_off(struct dc_link *link) +{ + struct dc_stream_state *stream_state; + struct amdgpu_dm_connector *aconnector = link->priv; + struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); + struct dc_stream_update stream_update; + bool dpms_off = true; + + memset(&stream_update, 0, sizeof(stream_update)); + stream_update.dpms_off = &dpms_off; + + mutex_lock(&adev->dm.dc_lock); + stream_state = dc_stream_find_from_link(link); + + if (stream_state == NULL) { + DRM_DEBUG_DRIVER("Error finding stream state associated with link!\n"); + mutex_unlock(&adev->dm.dc_lock); + return; + } + + stream_update.stream = stream_state; + dc_commit_updates_for_stream(stream_state->ctx->dc, NULL, 0, + stream_state, &stream_update, + stream_state->ctx->dc->current_state); + mutex_unlock(&adev->dm.dc_lock); +} + static int dm_resume(void *handle) { struct amdgpu_device *adev = handle; @@ -2098,9 +2205,10 @@ const struct amdgpu_ip_block_version dm_ip_block = static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = { .fb_create = amdgpu_display_user_framebuffer_create, + .get_format_info = amd_get_format_info, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = amdgpu_dm_atomic_check, - .atomic_commit = amdgpu_dm_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = { @@ -2318,6 +2426,7 @@ static void handle_hpd_irq(void *param) enum dc_connection_type new_connection_type = dc_connection_none; #ifdef CONFIG_DRM_AMD_DC_HDCP struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); #endif /* @@ -2327,8 +2436,10 @@ static void handle_hpd_irq(void *param) mutex_lock(&aconnector->hpd_lock); #ifdef CONFIG_DRM_AMD_DC_HDCP - if (adev->dm.hdcp_workqueue) + if (adev->dm.hdcp_workqueue) { hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index); + dm_con_state->update_hdcp = true; + } #endif if (aconnector->fake_enable) aconnector->fake_enable = false; @@ -2348,8 +2459,11 @@ static void handle_hpd_irq(void *param) drm_kms_helper_hotplug_event(dev); } else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) { - amdgpu_dm_update_connector_after_detect(aconnector); + if (new_connection_type == dc_connection_none && + aconnector->dc_link->type == dc_connection_none) + dm_set_dpms_off(aconnector->dc_link); + amdgpu_dm_update_connector_after_detect(aconnector); drm_modeset_lock_all(dev); dm_restore_drm_connector_state(dev, connector); @@ -2447,13 +2561,12 @@ static void handle_hpd_rx_irq(void *param) struct drm_device *dev = connector->dev; struct dc_link *dc_link = aconnector->dc_link; bool is_mst_root_connector = aconnector->mst_mgr.mst_state; + bool result = false; enum dc_connection_type new_connection_type = dc_connection_none; -#ifdef CONFIG_DRM_AMD_DC_HDCP - union hpd_irq_data hpd_irq_data; struct amdgpu_device *adev = drm_to_adev(dev); + union hpd_irq_data hpd_irq_data; memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); -#endif /* * TODO:Temporary add mutex to protect hpd interrupt not have a gpio @@ -2463,13 +2576,31 @@ static void handle_hpd_rx_irq(void *param) if (dc_link->type != dc_connection_mst_branch) mutex_lock(&aconnector->hpd_lock); + read_hpd_rx_irq_data(dc_link, &hpd_irq_data); + if ((dc_link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) || + (dc_link->type == dc_connection_mst_branch)) { + if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) { + result = true; + dm_handle_hpd_rx_irq(aconnector); + goto out; + } else if (hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { + result = false; + dm_handle_hpd_rx_irq(aconnector); + goto out; + } + } + + mutex_lock(&adev->dm.dc_lock); #ifdef CONFIG_DRM_AMD_DC_HDCP - if (dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, NULL) && + result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, NULL); #else - if (dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL) && + result = dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL); #endif - !is_mst_root_connector) { + mutex_unlock(&adev->dm.dc_lock); + +out: + if (result && !is_mst_root_connector) { /* Downstream Port status changed. */ if (!dc_link_detect_sink(dc_link, &new_connection_type)) DRM_ERROR("KMS: Failed to detect connector\n"); @@ -2509,9 +2640,6 @@ static void handle_hpd_rx_irq(void *param) hdcp_handle_cpirq(adev->dm.hdcp_workqueue, aconnector->base.index); } #endif - if ((dc_link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) || - (dc_link->type == dc_connection_mst_branch)) - dm_handle_hpd_rx_irq(aconnector); if (dc_link->type != dc_connection_mst_branch) { drm_dp_cec_irq(&aconnector->dm_dp_aux.aux); @@ -3401,10 +3529,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_RENOIR: -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: -#endif + case CHIP_DIMGREY_CAVEFISH: + case CHIP_VANGOGH: if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -3563,31 +3691,27 @@ static int dm_early_init(void *handle) break; #if defined(CONFIG_DRM_AMD_DC_DCN) case CHIP_RAVEN: + case CHIP_RENOIR: + case CHIP_VANGOGH: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; adev->mode_info.num_dig = 4; break; -#endif case CHIP_NAVI10: case CHIP_NAVI12: -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: -#endif adev->mode_info.num_crtc = 6; adev->mode_info.num_hpd = 6; adev->mode_info.num_dig = 6; break; case CHIP_NAVI14: + case CHIP_DIMGREY_CAVEFISH: adev->mode_info.num_crtc = 5; adev->mode_info.num_hpd = 5; adev->mode_info.num_dig = 5; break; - case CHIP_RENOIR: - adev->mode_info.num_crtc = 4; - adev->mode_info.num_hpd = 4; - adev->mode_info.num_dig = 4; - break; +#endif default: DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type); return -EINVAL; @@ -3691,78 +3815,84 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, return 0; } -static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb, - uint64_t *tiling_flags, bool *tmz_surface) +static void +fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info, + uint64_t tiling_flags) { - struct amdgpu_bo *rbo; - int r; - - if (!amdgpu_fb) { - *tiling_flags = 0; - *tmz_surface = false; - return 0; - } + /* Fill GFX8 params */ + if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) { + unsigned int bankw, bankh, mtaspect, tile_split, num_banks; - rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]); - r = amdgpu_bo_reserve(rbo, false); + bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH); + bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT); + mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT); + tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT); + num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS); - if (unlikely(r)) { - /* Don't show error message when returning -ERESTARTSYS */ - if (r != -ERESTARTSYS) - DRM_ERROR("Unable to reserve buffer: %d\n", r); - return r; + /* XXX fix me for VI */ + tiling_info->gfx8.num_banks = num_banks; + tiling_info->gfx8.array_mode = + DC_ARRAY_2D_TILED_THIN1; + tiling_info->gfx8.tile_split = tile_split; + tiling_info->gfx8.bank_width = bankw; + tiling_info->gfx8.bank_height = bankh; + tiling_info->gfx8.tile_aspect = mtaspect; + tiling_info->gfx8.tile_mode = + DC_ADDR_SURF_MICRO_TILING_DISPLAY; + } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) + == DC_ARRAY_1D_TILED_THIN1) { + tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1; } - if (tiling_flags) - amdgpu_bo_get_tiling_flags(rbo, tiling_flags); - - if (tmz_surface) - *tmz_surface = amdgpu_bo_encrypted(rbo); - - amdgpu_bo_unreserve(rbo); - - return r; + tiling_info->gfx8.pipe_config = + AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG); } -static inline uint64_t get_dcc_address(uint64_t address, uint64_t tiling_flags) -{ - uint32_t offset = AMDGPU_TILING_GET(tiling_flags, DCC_OFFSET_256B); - - return offset ? (address + offset * 256) : 0; +static void +fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, + union dc_tiling_info *tiling_info) +{ + tiling_info->gfx9.num_pipes = + adev->gfx.config.gb_addr_config_fields.num_pipes; + tiling_info->gfx9.num_banks = + adev->gfx.config.gb_addr_config_fields.num_banks; + tiling_info->gfx9.pipe_interleave = + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size; + tiling_info->gfx9.num_shader_engines = + adev->gfx.config.gb_addr_config_fields.num_se; + tiling_info->gfx9.max_compressed_frags = + adev->gfx.config.gb_addr_config_fields.max_compress_frags; + tiling_info->gfx9.num_rb_per_se = + adev->gfx.config.gb_addr_config_fields.num_rb_per_se; + tiling_info->gfx9.shaderEnable = 1; + if (adev->asic_type == CHIP_SIENNA_CICHLID || + adev->asic_type == CHIP_NAVY_FLOUNDER || + adev->asic_type == CHIP_DIMGREY_CAVEFISH || + adev->asic_type == CHIP_VANGOGH) + tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; } static int -fill_plane_dcc_attributes(struct amdgpu_device *adev, - const struct amdgpu_framebuffer *afb, - const enum surface_pixel_format format, - const enum dc_rotation_angle rotation, - const struct plane_size *plane_size, - const union dc_tiling_info *tiling_info, - const uint64_t info, - struct dc_plane_dcc_param *dcc, - struct dc_plane_address *address, - bool force_disable_dcc) +validate_dcc(struct amdgpu_device *adev, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const union dc_tiling_info *tiling_info, + const struct dc_plane_dcc_param *dcc, + const struct dc_plane_address *address, + const struct plane_size *plane_size) { struct dc *dc = adev->dm.dc; struct dc_dcc_surface_param input; struct dc_surface_dcc_cap output; - uint32_t offset = AMDGPU_TILING_GET(info, DCC_OFFSET_256B); - uint32_t i64b = AMDGPU_TILING_GET(info, DCC_INDEPENDENT_64B) != 0; - uint64_t dcc_address; memset(&input, 0, sizeof(input)); memset(&output, 0, sizeof(output)); - if (force_disable_dcc) - return 0; - - if (!offset) + if (!dcc->enable) return 0; - if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return 0; - - if (!dc->cap_funcs.get_dcc_compression_cap) + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || + !dc->cap_funcs.get_dcc_compression_cap) return -EINVAL; input.format = format; @@ -3781,17 +3911,422 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev, if (!output.capable) return -EINVAL; - if (i64b == 0 && output.grph.rgb.independent_64b_blks != 0) + if (dcc->independent_64b_blks == 0 && + output.grph.rgb.independent_64b_blks != 0) return -EINVAL; - dcc->enable = 1; - dcc->meta_pitch = - AMDGPU_TILING_GET(info, DCC_PITCH_MAX) + 1; - dcc->independent_64b_blks = i64b; + return 0; +} + +static bool +modifier_has_dcc(uint64_t modifier) +{ + return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier); +} + +static unsigned +modifier_gfx9_swizzle_mode(uint64_t modifier) +{ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return 0; + + return AMD_FMT_MOD_GET(TILE, modifier); +} + +static const struct drm_format_info * +amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd) +{ + return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]); +} + +static void +fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, + union dc_tiling_info *tiling_info, + uint64_t modifier) +{ + unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); + unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); + unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier); + unsigned int pipes_log2 = min(4u, mod_pipe_xor_bits); + + fill_gfx9_tiling_info_from_device(adev, tiling_info); + + if (!IS_AMD_FMT_MOD(modifier)) + return; + + tiling_info->gfx9.num_pipes = 1u << pipes_log2; + tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2); + + if (adev->family >= AMDGPU_FAMILY_NV) { + tiling_info->gfx9.num_pkrs = 1u << pkrs_log2; + } else { + tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits; + + /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */ + } +} + +enum dm_micro_swizzle { + MICRO_SWIZZLE_Z = 0, + MICRO_SWIZZLE_S = 1, + MICRO_SWIZZLE_D = 2, + MICRO_SWIZZLE_R = 3 +}; + +static bool dm_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) +{ + struct amdgpu_device *adev = drm_to_adev(plane->dev); + const struct drm_format_info *info = drm_format_info(format); + + enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3; + + if (!info) + return false; + + /* + * We always have to allow this modifier, because core DRM still + * checks LINEAR support if userspace does not provide modifers. + */ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + /* + * The arbitrary tiling support for multiplane formats has not been hooked + * up. + */ + if (info->num_planes > 1) + return false; - dcc_address = get_dcc_address(afb->address, info); - address->grph.meta_addr.low_part = lower_32_bits(dcc_address); - address->grph.meta_addr.high_part = upper_32_bits(dcc_address); + /* + * For D swizzle the canonical modifier depends on the bpp, so check + * it here. + */ + if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 && + adev->family >= AMDGPU_FAMILY_NV) { + if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4) + return false; + } + + if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D && + info->cpp[0] < 8) + return false; + + if (modifier_has_dcc(modifier)) { + /* Per radeonsi comments 16/64 bpp are more complicated. */ + if (info->cpp[0] != 4) + return false; + } + + return true; +} + +static void +add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod) +{ + if (!*mods) + return; + + if (*cap - *size < 1) { + uint64_t new_cap = *cap * 2; + uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL); + + if (!new_mods) { + kfree(*mods); + *mods = NULL; + return; + } + + memcpy(new_mods, *mods, sizeof(uint64_t) * *size); + kfree(*mods); + *mods = new_mods; + *cap = new_cap; + } + + (*mods)[*size] = mod; + *size += 1; +} + +static void +add_gfx9_modifiers(const struct amdgpu_device *adev, + uint64_t **mods, uint64_t *size, uint64_t *capacity) +{ + int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); + int pipe_xor_bits = min(8, pipes + + ilog2(adev->gfx.config.gb_addr_config_fields.num_se)); + int bank_xor_bits = min(8 - pipe_xor_bits, + ilog2(adev->gfx.config.gb_addr_config_fields.num_banks)); + int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) + + ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se); + + + if (adev->family == AMDGPU_FAMILY_RV) { + /* Raven2 and later */ + bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81; + + /* + * No _D DCC swizzles yet because we only allow 32bpp, which + * doesn't support _D on DCN + */ + + if (has_constant_encode) { + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1)); + } + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0)); + + if (has_constant_encode) { + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_RETILE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | + + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | + AMD_FMT_MOD_SET(RB, rb) | + AMD_FMT_MOD_SET(PIPE, pipes)); + } + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_RETILE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) | + AMD_FMT_MOD_SET(RB, rb) | + AMD_FMT_MOD_SET(PIPE, pipes)); + } + + /* + * Only supported for 64bpp on Raven, will be filtered on format in + * dm_plane_format_mod_supported. + */ + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits)); + + if (adev->family == AMDGPU_FAMILY_RV) { + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits)); + } + + /* + * Only supported for 64bpp on Raven, will be filtered on format in + * dm_plane_format_mod_supported. + */ + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); + + if (adev->family == AMDGPU_FAMILY_RV) { + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); + } +} + +static void +add_gfx10_1_modifiers(const struct amdgpu_device *adev, + uint64_t **mods, uint64_t *size, uint64_t *capacity) +{ + int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_RETILE, 1) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); + + + /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */ + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); +} + +static void +add_gfx10_3_modifiers(const struct amdgpu_device *adev, + uint64_t **mods, uint64_t *size, uint64_t *capacity) +{ + int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); + int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(PACKERS, pkrs) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(PACKERS, pkrs) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_RETILE, 1) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(PACKERS, pkrs)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(PACKERS, pkrs)); + + /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */ + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); +} + +static int +get_plane_modifiers(const struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) +{ + uint64_t size = 0, capacity = 128; + *mods = NULL; + + /* We have not hooked up any pre-GFX9 modifiers. */ + if (adev->family < AMDGPU_FAMILY_AI) + return 0; + + *mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL); + + if (plane_type == DRM_PLANE_TYPE_CURSOR) { + add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR); + add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID); + return *mods ? 0 : -ENOMEM; + } + + switch (adev->family) { + case AMDGPU_FAMILY_AI: + case AMDGPU_FAMILY_RV: + add_gfx9_modifiers(adev, mods, &size, &capacity); + break; + case AMDGPU_FAMILY_NV: + case AMDGPU_FAMILY_VGH: + if (adev->asic_type >= CHIP_SIENNA_CICHLID) + add_gfx10_3_modifiers(adev, mods, &size, &capacity); + else + add_gfx10_1_modifiers(adev, mods, &size, &capacity); + break; + } + + add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR); + + /* INVALID marks the end of the list. */ + add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID); + + if (!*mods) + return -ENOMEM; + + return 0; +} + +static int +fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct plane_size *plane_size, + union dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address, + const bool force_disable_dcc) +{ + const uint64_t modifier = afb->base.modifier; + int ret; + + fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier); + tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier); + + if (modifier_has_dcc(modifier) && !force_disable_dcc) { + uint64_t dcc_address = afb->address + afb->base.offsets[1]; + + dcc->enable = 1; + dcc->meta_pitch = afb->base.pitches[1]; + dcc->independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier); + + address->grph.meta_addr.low_part = lower_32_bits(dcc_address); + address->grph.meta_addr.high_part = upper_32_bits(dcc_address); + } + + ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size); + if (ret) + return ret; return 0; } @@ -3820,6 +4355,8 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, address->tmz_surface = tmz_surface; if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + uint64_t addr = afb->address + fb->offsets[0]; + plane_size->surface_size.x = 0; plane_size->surface_size.y = 0; plane_size->surface_size.width = fb->width; @@ -3828,9 +4365,10 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, fb->pitches[0] / fb->format->cpp[0]; address->type = PLN_ADDR_TYPE_GRAPHICS; - address->grph.addr.low_part = lower_32_bits(afb->address); - address->grph.addr.high_part = upper_32_bits(afb->address); + address->grph.addr.low_part = lower_32_bits(addr); + address->grph.addr.high_part = upper_32_bits(addr); } else if (format < SURFACE_PIXEL_FORMAT_INVALID) { + uint64_t luma_addr = afb->address + fb->offsets[0]; uint64_t chroma_addr = afb->address + fb->offsets[1]; plane_size->surface_size.x = 0; @@ -3851,83 +4389,25 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; address->video_progressive.luma_addr.low_part = - lower_32_bits(afb->address); + lower_32_bits(luma_addr); address->video_progressive.luma_addr.high_part = - upper_32_bits(afb->address); + upper_32_bits(luma_addr); address->video_progressive.chroma_addr.low_part = lower_32_bits(chroma_addr); address->video_progressive.chroma_addr.high_part = upper_32_bits(chroma_addr); } - /* Fill GFX8 params */ - if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) { - unsigned int bankw, bankh, mtaspect, tile_split, num_banks; - - bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH); - bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT); - mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT); - tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT); - num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS); - - /* XXX fix me for VI */ - tiling_info->gfx8.num_banks = num_banks; - tiling_info->gfx8.array_mode = - DC_ARRAY_2D_TILED_THIN1; - tiling_info->gfx8.tile_split = tile_split; - tiling_info->gfx8.bank_width = bankw; - tiling_info->gfx8.bank_height = bankh; - tiling_info->gfx8.tile_aspect = mtaspect; - tiling_info->gfx8.tile_mode = - DC_ADDR_SURF_MICRO_TILING_DISPLAY; - } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) - == DC_ARRAY_1D_TILED_THIN1) { - tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1; - } - - tiling_info->gfx8.pipe_config = - AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG); - - if (adev->asic_type == CHIP_VEGA10 || - adev->asic_type == CHIP_VEGA12 || - adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_NAVI10 || - adev->asic_type == CHIP_NAVI14 || - adev->asic_type == CHIP_NAVI12 || -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) - adev->asic_type == CHIP_SIENNA_CICHLID || - adev->asic_type == CHIP_NAVY_FLOUNDER || -#endif - adev->asic_type == CHIP_RENOIR || - adev->asic_type == CHIP_RAVEN) { - /* Fill GFX9 params */ - tiling_info->gfx9.num_pipes = - adev->gfx.config.gb_addr_config_fields.num_pipes; - tiling_info->gfx9.num_banks = - adev->gfx.config.gb_addr_config_fields.num_banks; - tiling_info->gfx9.pipe_interleave = - adev->gfx.config.gb_addr_config_fields.pipe_interleave_size; - tiling_info->gfx9.num_shader_engines = - adev->gfx.config.gb_addr_config_fields.num_se; - tiling_info->gfx9.max_compressed_frags = - adev->gfx.config.gb_addr_config_fields.max_compress_frags; - tiling_info->gfx9.num_rb_per_se = - adev->gfx.config.gb_addr_config_fields.num_rb_per_se; - tiling_info->gfx9.swizzle = - AMDGPU_TILING_GET(tiling_flags, SWIZZLE_MODE); - tiling_info->gfx9.shaderEnable = 1; - -#ifdef CONFIG_DRM_AMD_DC_DCN3_0 - if (adev->asic_type == CHIP_SIENNA_CICHLID || - adev->asic_type == CHIP_NAVY_FLOUNDER) - tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; -#endif - ret = fill_plane_dcc_attributes(adev, afb, format, rotation, - plane_size, tiling_info, - tiling_flags, dcc, address, - force_disable_dcc); + if (adev->family >= AMDGPU_FAMILY_AI) { + ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format, + rotation, plane_size, + tiling_info, dcc, + address, + force_disable_dcc); if (ret) return ret; + } else { + fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags); } return 0; @@ -4127,7 +4607,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, struct drm_crtc_state *crtc_state) { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); - struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb; struct dc_scaling_info scaling_info; struct dc_plane_info plane_info; int ret; @@ -4144,10 +4624,10 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend; ret = fill_dc_plane_info_and_addr(adev, plane_state, - dm_plane_state->tiling_flags, + afb->tiling_flags, &plane_info, &dc_plane_state->address, - dm_plane_state->tmz_surface, + afb->tmz_surface, force_disable_dcc); if (ret) return ret; @@ -4640,9 +5120,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, int preferred_refresh = 0; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_dec_dpcd_caps dsc_caps; -#endif uint32_t link_bandwidth_kbps; - +#endif struct dc_sink *sink = NULL; if (aconnector == NULL) { DRM_ERROR("aconnector is NULL!\n"); @@ -4724,11 +5203,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, &dsc_caps); -#endif link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, dc_link_get_link_cap(aconnector->dc_link)); -#if defined(CONFIG_DRM_AMD_DC_DCN) if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) { /* Set DSC policy according to dsc_clock_en */ dc_dsc_policy_set_enable_dsc_when_not_needed( @@ -4737,6 +5214,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], &dsc_caps, aconnector->dc_link->ctx->dc->debug.dsc_min_slice_height_override, + 0, link_bandwidth_kbps, &stream->timing, &stream->timing.dsc_cfg)) @@ -4855,12 +5333,64 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) state->crc_src = cur->crc_src; state->cm_has_degamma = cur->cm_has_degamma; state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; - +#ifdef CONFIG_DEBUG_FS + state->crc_window = cur->crc_window; +#endif /* TODO Duplicate dc_stream after objects are stream object is flattened */ return &state->base; } +#ifdef CONFIG_DEBUG_FS +static int amdgpu_dm_crtc_atomic_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = crtc->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_crtc_state *dm_new_state = + to_dm_crtc_state(crtc_state); + + if (property == adev->dm.crc_win_x_start_property) + dm_new_state->crc_window.x_start = val; + else if (property == adev->dm.crc_win_y_start_property) + dm_new_state->crc_window.y_start = val; + else if (property == adev->dm.crc_win_x_end_property) + dm_new_state->crc_window.x_end = val; + else if (property == adev->dm.crc_win_y_end_property) + dm_new_state->crc_window.y_end = val; + else + return -EINVAL; + + return 0; +} + +static int amdgpu_dm_crtc_atomic_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *dev = crtc->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_crtc_state *dm_state = + to_dm_crtc_state(state); + + if (property == adev->dm.crc_win_x_start_property) + *val = dm_state->crc_window.x_start; + else if (property == adev->dm.crc_win_y_start_property) + *val = dm_state->crc_window.y_start; + else if (property == adev->dm.crc_win_x_end_property) + *val = dm_state->crc_window.x_end; + else if (property == adev->dm.crc_win_y_end_property) + *val = dm_state->crc_window.y_end; + else + return -EINVAL; + + return 0; +} +#endif + static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable) { enum dc_irq_source irq_source; @@ -4927,6 +5457,10 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .enable_vblank = dm_enable_vblank, .disable_vblank = dm_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, +#ifdef CONFIG_DEBUG_FS + .atomic_set_property = amdgpu_dm_crtc_atomic_set_property, + .atomic_get_property = amdgpu_dm_crtc_atomic_get_property, +#endif }; static enum drm_connector_status @@ -5315,7 +5849,8 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec dc_sink = to_amdgpu_dm_connector(connector)->dc_sink; - if (dc_sink == NULL) { + if (dc_sink == NULL && aconnector->base.force != DRM_FORCE_ON_DIGITAL && + aconnector->base.force != DRM_FORCE_ON) { DRM_ERROR("dc_sink is NULL!\n"); goto fail; } @@ -5421,6 +5956,8 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, struct drm_crtc_state *new_crtc_state; int ret; + trace_amdgpu_dm_connector_atomic_check(new_con_state); + if (!crtc) return 0; @@ -5519,17 +6056,21 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc, } static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) + struct drm_atomic_state *state) { + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, + crtc); struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc *dc = adev->dm.dc; - struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state); + struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); int ret = -EINVAL; - dm_update_crtc_active_planes(crtc, state); + trace_amdgpu_dm_crtc_atomic_check(crtc_state); + + dm_update_crtc_active_planes(crtc, crtc_state); if (unlikely(!dm_crtc_state->stream && - modeset_required(state, NULL, dm_crtc_state->stream))) { + modeset_required(crtc_state, NULL, dm_crtc_state->stream))) { WARN_ON(1); return ret; } @@ -5540,9 +6081,11 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, * planes are disabled, which is not supported by the hardware. And there is legacy * userspace which stops using the HW cursor altogether in response to the resulting EINVAL. */ - if (state->enable && - !(state->plane_mask & drm_plane_mask(crtc->primary))) + if (crtc_state->enable && + !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) { + DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n"); return -EINVAL; + } /* In some use cases, like reset, no stream is attached */ if (!dm_crtc_state->stream) @@ -5551,6 +6094,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK) return 0; + DRM_DEBUG_ATOMIC("Failed DC stream validation\n"); return ret; } @@ -5742,10 +6286,6 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) dc_plane_state_retain(dm_plane_state->dc_state); } - /* Framebuffer hasn't been updated yet, so retain old flags. */ - dm_plane_state->tiling_flags = old_dm_plane_state->tiling_flags; - dm_plane_state->tmz_surface = old_dm_plane_state->tmz_surface; - return &dm_plane_state->base; } @@ -5767,6 +6307,7 @@ static const struct drm_plane_funcs dm_plane_funcs = { .reset = dm_drm_plane_reset, .atomic_duplicate_state = dm_drm_plane_duplicate_state, .atomic_destroy_state = dm_drm_plane_destroy_state, + .format_mod_supported = dm_plane_format_mod_supported, }; static int dm_plane_helper_prepare_fb(struct drm_plane *plane, @@ -5850,10 +6391,10 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, fill_plane_buffer_attributes( adev, afb, plane_state->format, plane_state->rotation, - dm_plane_state_new->tiling_flags, + afb->tiling_flags, &plane_state->tiling_info, &plane_state->plane_size, &plane_state->dcc, &plane_state->address, - dm_plane_state_new->tmz_surface, force_disable_dcc); + afb->tmz_surface, force_disable_dcc); } return 0; @@ -5901,6 +6442,8 @@ static int dm_plane_atomic_check(struct drm_plane *plane, struct drm_crtc_state *new_crtc_state; int ret; + trace_amdgpu_dm_plane_atomic_check(state); + dm_plane_state = to_dm_plane_state(state); if (!dm_plane_state->dc_state) @@ -5941,6 +6484,8 @@ static void dm_plane_atomic_async_update(struct drm_plane *plane, struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(new_state->state, plane); + trace_amdgpu_dm_atomic_update_cursor(new_state); + swap(plane->state->fb, new_state->fb); plane->state->src_x = new_state->src_x; @@ -6059,13 +6604,19 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, int num_formats; int res = -EPERM; unsigned int supported_rotations; + uint64_t *modifiers = NULL; num_formats = get_plane_formats(plane, plane_cap, formats, ARRAY_SIZE(formats)); + res = get_plane_modifiers(dm->adev, plane->type, &modifiers); + if (res) + return res; + res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs, &dm_plane_funcs, formats, num_formats, - NULL, plane->type, NULL); + modifiers, plane->type, NULL); + kfree(modifiers); if (res) return res; @@ -6097,7 +6648,8 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; - if (dm->adev->asic_type >= CHIP_BONAIRE) + if (dm->adev->asic_type >= CHIP_BONAIRE && + plane->type != DRM_PLANE_TYPE_CURSOR) drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, supported_rotations); @@ -6110,6 +6662,25 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, return 0; } +#ifdef CONFIG_DEBUG_FS +static void attach_crtc_crc_properties(struct amdgpu_display_manager *dm, + struct amdgpu_crtc *acrtc) +{ + drm_object_attach_property(&acrtc->base.base, + dm->crc_win_x_start_property, + 0); + drm_object_attach_property(&acrtc->base.base, + dm->crc_win_y_start_property, + 0); + drm_object_attach_property(&acrtc->base.base, + dm->crc_win_x_end_property, + 0); + drm_object_attach_property(&acrtc->base.base, + dm->crc_win_y_end_property, + 0); +} +#endif + static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, struct drm_plane *plane, uint32_t crtc_index) @@ -6157,7 +6728,9 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES, true, MAX_COLOR_LUT_ENTRIES); drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); - +#ifdef CONFIG_DEBUG_FS + attach_crtc_crc_properties(dm, acrtc); +#endif return 0; fail: @@ -6351,7 +6924,7 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) encoder = amdgpu_dm_connector_to_encoder(connector); - if (!edid || !drm_edid_is_valid(edid)) { + if (!drm_edid_is_valid(edid)) { amdgpu_dm_connector->num_modes = drm_add_modes_noedid(connector, 640, 480); } else { @@ -6708,38 +7281,63 @@ static bool is_content_protection_different(struct drm_connector_state *state, const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); + /* Handle: Type0/1 change */ if (old_state->hdcp_content_type != state->hdcp_content_type && state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; return true; } - /* CP is being re enabled, ignore this */ + /* CP is being re enabled, ignore this + * + * Handles: ENABLED -> DESIRED + */ if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; return false; } - /* S3 resume case, since old state will always be 0 (UNDESIRED) and the restored state will be ENABLED */ + /* S3 resume case, since old state will always be 0 (UNDESIRED) and the restored state will be ENABLED + * + * Handles: UNDESIRED -> ENABLED + */ if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED && state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; /* Check if something is connected/enabled, otherwise we start hdcp but nothing is connected/enabled * hot-plug, headless s3, dpms + * + * Handles: DESIRED -> DESIRED (Special case) */ - if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && connector->dpms == DRM_MODE_DPMS_ON && - aconnector->dc_sink != NULL) + if (dm_con_state->update_hdcp && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && + connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) { + dm_con_state->update_hdcp = false; return true; + } + /* + * Handles: UNDESIRED -> UNDESIRED + * DESIRED -> DESIRED + * ENABLED -> ENABLED + */ if (old_state->content_protection == state->content_protection) return false; - if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + /* + * Handles: UNDESIRED -> DESIRED + * DESIRED -> UNDESIRED + * ENABLED -> UNDESIRED + */ + if (state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) return true; + /* + * Handles: DESIRED -> ENABLED + */ return false; } @@ -6851,7 +7449,7 @@ static void handle_cursor_update(struct drm_plane *plane, attributes.rotation_angle = 0; attributes.attribute_flags.value = 0; - attributes.pitch = attributes.width; + attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; if (crtc_state->stream) { mutex_lock(&adev->dm.dc_lock); @@ -7112,6 +7710,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_crtc *crtc = new_plane_state->crtc; struct drm_crtc_state *new_crtc_state; struct drm_framebuffer *fb = new_plane_state->fb; + struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)fb; bool plane_needs_flip; struct dc_plane_state *dc_plane; struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state); @@ -7166,10 +7765,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, fill_dc_plane_info_and_addr( dm->adev, new_plane_state, - dm_new_plane_state->tiling_flags, + afb->tiling_flags, &bundle->plane_infos[planes_count], &bundle->flip_addrs[planes_count].address, - dm_new_plane_state->tmz_surface, false); + afb->tmz_surface, false); DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n", new_plane_state->plane->index, @@ -7464,20 +8063,6 @@ 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 int amdgpu_dm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - /* - * Add check here for SoC's that support hardware cursor plane, to - * unset legacy_cursor_update - */ - - return drm_atomic_helper_commit(dev, state, nonblock); - - /*TODO Handle EINTR, reenable IRQ*/ -} - /** * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation. * @state: The atomic state to commit @@ -7504,6 +8089,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) int crtc_disable_count = 0; bool mode_set_reset_required = false; + trace_amdgpu_dm_atomic_commit_tail_begin(state); + drm_atomic_helper_update_legacy_modeset_state(dev, state); dm_state = dm_atomic_get_new_state(state); @@ -7552,6 +8139,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) new_crtc_state->active_changed, new_crtc_state->connectors_changed); + /* Disable cursor if disabling crtc */ + if (old_crtc_state->active && !new_crtc_state->active) { + struct dc_cursor_position position; + + memset(&position, 0, sizeof(position)); + mutex_lock(&dm->dc_lock); + dc_stream_set_cursor_position(dm_old_crtc_state->stream, &position); + mutex_unlock(&dm->dc_lock); + } + /* Copy all transient state flags into dc state */ if (dm_new_crtc_state->stream) { amdgpu_dm_crtc_copy_transient_flags(&dm_new_crtc_state->base, @@ -7651,6 +8248,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) { hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index); new_con_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + dm_new_con_state->update_hdcp = true; continue; } @@ -7769,6 +8367,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + bool configure_crc = false; dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); @@ -7778,21 +8377,30 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dc_stream_retain(dm_new_crtc_state->stream); acrtc->dm_irq_params.stream = dm_new_crtc_state->stream; manage_dm_interrupts(adev, acrtc, true); - + } #ifdef CONFIG_DEBUG_FS + if (new_crtc_state->active && + amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) { /** * Frontend may have changed so reapply the CRC capture * settings for the stream. */ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) { - amdgpu_dm_crtc_configure_crc_source( - crtc, dm_new_crtc_state, - dm_new_crtc_state->crc_src); + if (amdgpu_dm_crc_window_is_default(dm_new_crtc_state)) { + if (!old_crtc_state->active || drm_atomic_crtc_needs_modeset(new_crtc_state)) + configure_crc = true; + } else { + if (amdgpu_dm_crc_window_changed(dm_new_crtc_state, dm_old_crtc_state)) + configure_crc = true; } -#endif + + if (configure_crc) + amdgpu_dm_crtc_configure_crc_source( + crtc, dm_new_crtc_state, dm_new_crtc_state->crc_src); } +#endif } for_each_new_crtc_in_state(state, crtc, new_crtc_state, j) @@ -7833,6 +8441,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_cleanup_planes(dev, state); + /* return the stolen vga memory back to VRAM */ + if (!adev->mman.keep_stolen_vga_memory) + amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL); + amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); + /* * Finally, drop a runtime PM reference for each newly disabled CRTC, * so we can put the GPU into runtime suspend if we're not driving any @@ -8310,8 +8923,7 @@ static bool should_reset_plane(struct drm_atomic_state *state, * TODO: Come up with a more elegant solution for this. */ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { - struct dm_plane_state *old_dm_plane_state, *new_dm_plane_state; - + struct amdgpu_framebuffer *old_afb, *new_afb; if (other->type == DRM_PLANE_TYPE_CURSOR) continue; @@ -8355,18 +8967,79 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (old_other_state->fb->format != new_other_state->fb->format) return true; - old_dm_plane_state = to_dm_plane_state(old_other_state); - new_dm_plane_state = to_dm_plane_state(new_other_state); + old_afb = (struct amdgpu_framebuffer *)old_other_state->fb; + new_afb = (struct amdgpu_framebuffer *)new_other_state->fb; /* Tiling and DCC changes also require bandwidth updates. */ - if (old_dm_plane_state->tiling_flags != - new_dm_plane_state->tiling_flags) + if (old_afb->tiling_flags != new_afb->tiling_flags || + old_afb->base.modifier != new_afb->base.modifier) return true; } return false; } +static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, + struct drm_plane_state *new_plane_state, + struct drm_framebuffer *fb) +{ + struct amdgpu_device *adev = drm_to_adev(new_acrtc->base.dev); + struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb); + unsigned int pitch; + bool linear; + + 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", + 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"); + return -EINVAL; + } + + /* Pitch in pixels */ + pitch = fb->pitches[0] / fb->format->cpp[0]; + + if (fb->width != pitch) { + DRM_DEBUG_ATOMIC("Cursor FB width %d doesn't match pitch %d", + fb->width, pitch); + return -EINVAL; + } + + switch (pitch) { + case 64: + case 128: + case 256: + /* FB pitch is supported by cursor plane */ + break; + default: + DRM_DEBUG_ATOMIC("Bad cursor FB pitch %d px\n", pitch); + return -EINVAL; + } + + /* Core DRM takes care of checking FB modifiers, so we only need to + * check tiling flags when the FB doesn't have a modifier. */ + if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) { + if (adev->family < AMDGPU_FAMILY_AI) { + linear = AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_2D_TILED_THIN1 && + AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 && + AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0; + } else { + linear = AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0; + } + if (!linear) { + DRM_DEBUG_ATOMIC("Cursor FB not linear"); + return -EINVAL; + } + } + + return 0; +} + static int dm_update_plane_state(struct dc *dc, struct drm_atomic_state *state, struct drm_plane *plane, @@ -8391,7 +9064,6 @@ static int dm_update_plane_state(struct dc *dc, dm_new_plane_state = to_dm_plane_state(new_plane_state); dm_old_plane_state = to_dm_plane_state(old_plane_state); - /*TODO Implement better atomic check for cursor plane */ if (plane->type == DRM_PLANE_TYPE_CURSOR) { if (!enable || !new_plane_crtc || drm_atomic_plane_disabling(plane->state, new_plane_state)) @@ -8399,13 +9071,18 @@ static int dm_update_plane_state(struct dc *dc, new_acrtc = to_amdgpu_crtc(new_plane_crtc); - if ((new_plane_state->crtc_w > new_acrtc->max_cursor_width) || - (new_plane_state->crtc_h > new_acrtc->max_cursor_height)) { - DRM_DEBUG_ATOMIC("Bad cursor size %d x %d\n", - new_plane_state->crtc_w, new_plane_state->crtc_h); + if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) { + DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); return -EINVAL; } + if (new_plane_state->fb) { + ret = dm_check_cursor_fb(new_acrtc, new_plane_state, + new_plane_state->fb); + if (ret) + return ret; + } + return 0; } @@ -8527,6 +9204,43 @@ static int dm_update_plane_state(struct dc *dc, return ret; } +static int dm_check_crtc_cursor(struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_crtc_state *new_crtc_state) +{ + struct drm_plane_state *new_cursor_state, *new_primary_state; + int cursor_scale_w, cursor_scale_h, primary_scale_w, primary_scale_h; + + /* On DCE and DCN there is no dedicated hardware cursor plane. We get a + * cursor per pipe but it's going to inherit the scaling and + * positioning from the underlying pipe. Check the cursor plane's + * blending properties match the primary plane's. */ + + new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor); + new_primary_state = drm_atomic_get_new_plane_state(state, crtc->primary); + if (!new_cursor_state || !new_primary_state || !new_cursor_state->fb) { + return 0; + } + + cursor_scale_w = new_cursor_state->crtc_w * 1000 / + (new_cursor_state->src_w >> 16); + cursor_scale_h = new_cursor_state->crtc_h * 1000 / + (new_cursor_state->src_h >> 16); + + primary_scale_w = new_primary_state->crtc_w * 1000 / + (new_primary_state->src_w >> 16); + primary_scale_h = new_primary_state->crtc_h * 1000 / + (new_primary_state->src_h >> 16); + + if (cursor_scale_w != primary_scale_w || + cursor_scale_h != primary_scale_h) { + DRM_DEBUG_ATOMIC("Cursor plane scaling doesn't match primary plane\n"); + return -EINVAL; + } + + return 0; +} + #if defined(CONFIG_DRM_AMD_DC_DCN) static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc) { @@ -8591,8 +9305,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, enum dc_status status; int ret, i; bool lock_and_validation_needed = false; + struct dm_crtc_state *dm_old_crtc_state; - amdgpu_check_debugfs_connector_property_change(adev, state); + trace_amdgpu_dm_atomic_check_begin(state); ret = drm_atomic_helper_check_modeset(dev, state); if (ret) @@ -8633,9 +9348,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } #endif for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->color_mgmt_changed && - old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled) + old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled && + dm_old_crtc_state->dsc_force_changed == false) continue; if (!new_crtc_state->enable) @@ -8648,6 +9366,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = drm_atomic_add_affected_planes(state, crtc); if (ret) goto fail; + + if (dm_old_crtc_state->dsc_force_changed && new_crtc_state) + new_crtc_state->mode_changed = true; } /* @@ -8686,17 +9407,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } } - /* Prepass for updating tiling flags on new planes. */ - for_each_new_plane_in_state(state, plane, new_plane_state, i) { - struct dm_plane_state *new_dm_plane_state = to_dm_plane_state(new_plane_state); - struct amdgpu_framebuffer *new_afb = to_amdgpu_framebuffer(new_plane_state->fb); - - ret = get_fb_info(new_afb, &new_dm_plane_state->tiling_flags, - &new_dm_plane_state->tmz_surface); - if (ret) - goto fail; - } - /* Remove exiting planes if they are modified */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ret = dm_update_plane_state(dc, state, plane, @@ -8746,6 +9456,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (ret) goto fail; + /* Check cursor planes scaling */ + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + ret = dm_check_crtc_cursor(state, crtc, new_crtc_state); + if (ret) + goto fail; + } + if (state->legacy_cursor_update) { /* * This is a fast cursor update coming from the plane update @@ -8890,6 +9607,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, /* Must be success */ WARN_ON(ret); + + trace_amdgpu_dm_atomic_check_finish(state, ret); + return ret; fail: @@ -8900,6 +9620,8 @@ fail: else DRM_DEBUG_DRIVER("Atomic check failed with err: %d \n", ret); + trace_amdgpu_dm_atomic_check_finish(state, ret); + return ret; } @@ -9117,7 +9839,7 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) &stream, 1, ¶ms); - return dc_link_set_psr_allow_active(link, true, false); + return dc_link_set_psr_allow_active(link, true, false, false); } /* @@ -9131,7 +9853,7 @@ static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream) DRM_DEBUG_DRIVER("Disabling psr...\n"); - return dc_link_set_psr_allow_active(stream->link, false, true); + return dc_link_set_psr_allow_active(stream->link, false, true, false); } /* @@ -9164,3 +9886,41 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) } mutex_unlock(&adev->dm.dc_lock); } + +void dm_write_reg_func(const struct dc_context *ctx, uint32_t address, + uint32_t value, const char *func_name) +{ +#ifdef DM_CHECK_ADDR_0 + if (address == 0) { + DC_ERR("invalid register write. address = 0"); + return; + } +#endif + cgs_write_register(ctx->cgs_device, address, value); + trace_amdgpu_dc_wreg(&ctx->perf_trace->write_count, address, value); +} + +uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address, + const char *func_name) +{ + uint32_t value; +#ifdef DM_CHECK_ADDR_0 + if (address == 0) { + DC_ERR("invalid register read; address = 0\n"); + return 0; + } +#endif + + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress && + !ctx->dmub_srv->reg_helper_offload.should_burst_write) { + ASSERT(false); + return 0; + } + + value = cgs_read_register(ctx->cgs_device, address); + + trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value); + + return value; +} 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 a8a0e8cb1a11..2ee6edb3df93 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -336,6 +336,32 @@ struct amdgpu_display_manager { */ const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; +#ifdef CONFIG_DEBUG_FS + /** + * @crc_win_x_start_property: + * + * X start of the crc calculation window + */ + struct drm_property *crc_win_x_start_property; + /** + * @crc_win_y_start_property: + * + * Y start of the crc calculation window + */ + struct drm_property *crc_win_y_start_property; + /** + * @crc_win_x_end_property: + * + * X end of the crc calculation window + */ + struct drm_property *crc_win_x_end_property; + /** + * @crc_win_y_end_property: + * + * Y end of the crc calculation window + */ + struct drm_property *crc_win_y_end_property; +#endif /** * @mst_encoders: * @@ -420,10 +446,17 @@ struct dc_plane_state; struct dm_plane_state { struct drm_plane_state base; struct dc_plane_state *dc_state; - uint64_t tiling_flags; - bool tmz_surface; }; +#ifdef CONFIG_DEBUG_FS +struct crc_rec { + uint16_t x_start; + uint16_t y_start; + uint16_t x_end; + uint16_t y_end; + }; +#endif + struct dm_crtc_state { struct drm_crtc_state base; struct dc_stream_state *stream; @@ -440,11 +473,15 @@ struct dm_crtc_state { bool freesync_timing_changed; bool freesync_vrr_info_changed; + bool dsc_force_changed; bool vrr_supported; struct mod_freesync_config freesync_config; struct dc_info_packet vrr_infopacket; int abm_level; +#ifdef CONFIG_DEBUG_FS + struct crc_rec crc_window; +#endif }; #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base) @@ -465,6 +502,9 @@ struct dm_connector_state { uint8_t underscan_hborder; bool underscan_enable; bool freesync_capable; +#ifdef CONFIG_DRM_AMD_DC_HDCP + bool update_hdcp; +#endif uint8_t abm_level; int vcpi_slots; uint64_t pbn; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 5df05f0d18bc..157fe4efbb59 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -119,7 +119,7 @@ static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size) return true; } -/** +/* * Convert the drm_color_lut to dc_gamma. The conversion depends on the size * of the lut - whether or not it's legacy. */ @@ -413,7 +413,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) /** * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. * @crtc: amdgpu_dm crtc state - * @ dc_plane_state: target DC surface + * @dc_plane_state: target DC surface * * Update the underlying dc_stream_state's input transfer function (ITF) in * preparation for hardware commit. The transfer function used depends on 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 d0699e98db92..7b886a779a8c 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 @@ -81,6 +81,41 @@ const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc, return pipe_crc_sources; } +static void amdgpu_dm_set_crc_window_default(struct dm_crtc_state *dm_crtc_state) +{ + dm_crtc_state->crc_window.x_start = 0; + dm_crtc_state->crc_window.y_start = 0; + dm_crtc_state->crc_window.x_end = 0; + dm_crtc_state->crc_window.y_end = 0; +} + +bool amdgpu_dm_crc_window_is_default(struct dm_crtc_state *dm_crtc_state) +{ + bool ret = true; + + if ((dm_crtc_state->crc_window.x_start != 0) || + (dm_crtc_state->crc_window.y_start != 0) || + (dm_crtc_state->crc_window.x_end != 0) || + (dm_crtc_state->crc_window.y_end != 0)) + ret = false; + + return ret; +} + +bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state, + struct dm_crtc_state *dm_old_crtc_state) +{ + bool ret = false; + + if ((dm_new_crtc_state->crc_window.x_start != dm_old_crtc_state->crc_window.x_start) || + (dm_new_crtc_state->crc_window.y_start != dm_old_crtc_state->crc_window.y_start) || + (dm_new_crtc_state->crc_window.x_end != dm_old_crtc_state->crc_window.x_end) || + (dm_new_crtc_state->crc_window.y_end != dm_old_crtc_state->crc_window.y_end)) + ret = true; + + return ret; +} + int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, size_t *values_cnt) @@ -105,6 +140,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, struct dc_stream_state *stream_state = dm_crtc_state->stream; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; + struct crc_params *crc_window = NULL, tmp_window; /* Configuration will be deferred to stream enable. */ if (!stream_state) @@ -113,9 +149,25 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, mutex_lock(&adev->dm.dc_lock); /* Enable CRTC CRC generation if necessary. */ - if (dm_is_crc_source_crtc(source)) { + if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { + if (!enable) + amdgpu_dm_set_crc_window_default(dm_crtc_state); + + if (!amdgpu_dm_crc_window_is_default(dm_crtc_state)) { + crc_window = &tmp_window; + + tmp_window.windowa_x_start = dm_crtc_state->crc_window.x_start; + tmp_window.windowa_y_start = dm_crtc_state->crc_window.y_start; + tmp_window.windowa_x_end = dm_crtc_state->crc_window.x_end; + tmp_window.windowa_y_end = dm_crtc_state->crc_window.y_end; + tmp_window.windowb_x_start = dm_crtc_state->crc_window.x_start; + tmp_window.windowb_y_start = dm_crtc_state->crc_window.y_start; + tmp_window.windowb_x_end = dm_crtc_state->crc_window.x_end; + tmp_window.windowb_y_end = dm_crtc_state->crc_window.y_end; + } + if (!dc_stream_configure_crc(stream_state->ctx->dc, - stream_state, enable, enable)) { + stream_state, crc_window, enable, enable)) { ret = -EINVAL; goto unlock; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index f7d731797d3f..0235bfb246e5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -47,6 +47,9 @@ static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source /* amdgpu_dm_crc.c */ #ifdef CONFIG_DEBUG_FS +bool amdgpu_dm_crc_window_is_default(struct dm_crtc_state *dm_crtc_state); +bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state, + struct dm_crtc_state *dm_old_crtc_state); int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, struct dm_crtc_state *dm_crtc_state, enum amdgpu_dm_pipe_crc_source source); 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 8cd646eef096..11459fb09a37 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 @@ -556,7 +556,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us bool disable_hpd = false; bool valid_test_pattern = false; uint8_t param_nums = 0; - /* init with defalut 80bit custom pattern */ + /* init with default 80bit custom pattern */ uint8_t custom_pattern[10] = { 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07 @@ -1253,6 +1253,10 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; struct pipe_ctx *pipe_ctx; int i; char *wr_buf = NULL; @@ -1295,6 +1299,25 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, if (!pipe_ctx || !pipe_ctx->stream) goto done; + // Get CRTC state + mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + if (param[0] == 1) aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE; else if (param[0] == 2) @@ -1302,6 +1325,14 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, else aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_DEFAULT; + dm_crtc_state->dsc_force_changed = true; + +unlock: + if (crtc) + drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); + done: kfree(wr_buf); return size; @@ -1408,6 +1439,10 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, { struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct pipe_ctx *pipe_ctx; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; int i; char *wr_buf = NULL; uint32_t wr_buf_size = 42; @@ -1449,6 +1484,25 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, if (!pipe_ctx || !pipe_ctx->stream) goto done; + // Safely get CRTC state + mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + if (param[0] > 0) aconnector->dsc_settings.dsc_num_slices_h = DIV_ROUND_UP( pipe_ctx->stream->timing.h_addressable, @@ -1456,6 +1510,14 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, else aconnector->dsc_settings.dsc_num_slices_h = 0; + dm_crtc_state->dsc_force_changed = true; + +unlock: + if (crtc) + drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); + done: kfree(wr_buf); return size; @@ -1561,6 +1623,10 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; struct pipe_ctx *pipe_ctx; int i; char *wr_buf = NULL; @@ -1603,6 +1669,25 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, if (!pipe_ctx || !pipe_ctx->stream) goto done; + // Get CRTC state + mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + if (param[0] > 0) aconnector->dsc_settings.dsc_num_slices_v = DIV_ROUND_UP( pipe_ctx->stream->timing.v_addressable, @@ -1610,6 +1695,14 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, else aconnector->dsc_settings.dsc_num_slices_v = 0; + dm_crtc_state->dsc_force_changed = true; + +unlock: + if (crtc) + drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); + done: kfree(wr_buf); return size; @@ -1708,6 +1801,10 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu size_t size, loff_t *pos) { struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; struct pipe_ctx *pipe_ctx; int i; char *wr_buf = NULL; @@ -1750,8 +1847,35 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu if (!pipe_ctx || !pipe_ctx->stream) goto done; + // Get CRTC state + mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + aconnector->dsc_settings.dsc_bits_per_pixel = param[0]; + dm_crtc_state->dsc_force_changed = true; + +unlock: + if (crtc) + drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); + done: kfree(wr_buf); return size; @@ -2209,11 +2333,11 @@ static int psr_get(void *data, u64 *val) { struct amdgpu_dm_connector *connector = data; struct dc_link *link = connector->dc_link; - uint32_t psr_state = 0; + enum dc_psr_state state = PSR_STATE0; - dc_link_get_psr_state(link, &psr_state); + dc_link_get_psr_state(link, &state); - *val = psr_state; + *val = state; return 0; } 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 d839eb14e3f0..f6f487e9fe2d 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 @@ -318,6 +318,7 @@ void dm_dtn_log_begin(struct dc_context *ctx, dm_dtn_log_append_v(ctx, log_ctx, "%s", msg); } +__printf(3, 4) void dm_dtn_log_append_v(struct dc_context *ctx, struct dc_log_buffer_ctx *log_ctx, const char *msg, ...) @@ -418,9 +419,10 @@ bool dm_helpers_dp_mst_start_top_mgr( void dm_helpers_dp_mst_stop_top_mgr( struct dc_context *ctx, - const struct dc_link *link) + struct dc_link *link) { struct amdgpu_dm_connector *aconnector = link->priv; + uint8_t i; if (!aconnector) { DRM_ERROR("Failed to find connector for link!"); @@ -430,8 +432,25 @@ void dm_helpers_dp_mst_stop_top_mgr( DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n", aconnector, aconnector->base.base.id); - if (aconnector->mst_mgr.mst_state == true) + if (aconnector->mst_mgr.mst_state == true) { drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false); + + for (i = 0; i < MAX_SINKS_PER_LINK; i++) { + if (link->remote_sinks[i] == NULL) + continue; + + if (link->remote_sinks[i]->sink_signal == + SIGNAL_TYPE_DISPLAY_PORT_MST) { + dc_link_remove_remote_sink(link, link->remote_sinks[i]); + + if (aconnector->dc_sink) { + dc_sink_release(aconnector->dc_sink); + aconnector->dc_sink = NULL; + aconnector->dc_link->cur_link_settings.lane_count = 0; + } + } + } + } } bool dm_helpers_dp_read_dpcd( @@ -627,7 +646,6 @@ void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks) { /* TODO: something */ } -#ifdef CONFIG_DRM_AMD_DC_DCN3_0 void *dm_helpers_allocate_gpu_mem( struct dc_context *ctx, @@ -646,4 +664,3 @@ void dm_helpers_free_gpu_mem( { // TODO } -#endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index eee19edeeee5..8ab0b9060d2b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -24,6 +24,7 @@ */ #include <linux/version.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_dp_mst_helper.h> #include <drm/drm_dp_helper.h> @@ -252,8 +253,10 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) static struct drm_encoder * dm_mst_atomic_best_encoder(struct drm_connector *connector, - struct drm_connector_state *connector_state) + struct drm_atomic_state *state) { + struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, + connector); struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc); @@ -500,6 +503,7 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p ¶ms[i].sink->dsc_caps.dsc_dec_caps, params[i].sink->ctx->dc->debug.dsc_min_slice_height_override, 0, + 0, params[i].timing, ¶ms[i].timing->dsc_cfg)) { params[i].timing->flags.DSC = 1; @@ -530,6 +534,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) param.sink->ctx->dc->res_pool->dscs[0], ¶m.sink->dsc_caps.dsc_dec_caps, param.sink->ctx->dc->debug.dsc_min_slice_height_override, + 0, (int) kbps, param.timing, &dsc_config); return dsc_config.bits_per_pixel; @@ -734,7 +739,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, params[count].num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel; params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported; - dc_dsc_get_policy_for_timing(params[count].timing, &dsc_policy); + dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy); if (!dc_dsc_compute_bandwidth_range( stream->sink->ctx->dc->res_pool->dscs[0], stream->sink->ctx->dc->debug.dsc_min_slice_height_override, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 6e575ffe34d0..607ec0999445 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -346,13 +346,6 @@ bool dm_pp_get_clock_levels_by_type( get_default_clock_levels(clk_type, dc_clks); return true; } - } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_clock_by_type) { - if (smu_get_clock_by_type(&adev->smu, - dc_to_pp_clock_type(clk_type), - &pp_clks)) { - get_default_clock_levels(clk_type, dc_clks); - return true; - } } pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); @@ -366,13 +359,6 @@ bool dm_pp_get_clock_levels_by_type( validation_clks.memory_max_clock = 80000; validation_clks.level = 0; } - } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_max_high_clocks) { - if (smu_get_max_high_clocks(&adev->smu, &validation_clks)) { - DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); - validation_clks.engine_max_clock = 72000; - validation_clks.memory_max_clock = 80000; - validation_clks.level = 0; - } } DRM_INFO("DM_PPLIB: Validation clocks:\n"); @@ -461,11 +447,6 @@ bool dm_pp_get_clock_levels_by_type_with_voltage( &pp_clk_info); if (ret) return false; - } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_clock_by_type_with_voltage) { - if (smu_get_clock_by_type_with_voltage(&adev->smu, - dc_to_pp_clock_type(clk_type), - &pp_clk_info)) - return false; } pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); @@ -477,7 +458,21 @@ bool dm_pp_notify_wm_clock_changes( const struct dc_context *ctx, struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) { - /* TODO: to be implemented */ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + /* + * Limit this watermark setting for Polaris for now + * TODO: expand this to other ASICs + */ + if ((adev->asic_type >= CHIP_POLARIS10) && (adev->asic_type <= CHIP_VEGAM) + && pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges) { + if (!pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, + (void *)wm_with_clock_ranges)) + return true; + } + return false; } @@ -528,8 +523,6 @@ bool dm_pp_get_static_clocks( ret = adev->powerplay.pp_funcs->get_current_clocks( adev->powerplay.pp_handle, &pp_clk_info); - else if (adev->smu.ppt_funcs) - ret = smu_get_current_clocks(&adev->smu, &pp_clk_info); else return false; if (ret) @@ -542,7 +535,7 @@ bool dm_pp_get_static_clocks( return true; } -void pp_rv_set_wm_ranges(struct pp_smu *pp, +static void pp_rv_set_wm_ranges(struct pp_smu *pp, struct pp_smu_wm_range_sets *ranges) { const struct dc_context *ctx = pp->dm; @@ -594,7 +587,7 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp, &wm_with_clock_ranges); } -void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +static void pp_rv_set_pme_wa_enable(struct pp_smu *pp) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -603,11 +596,9 @@ void pp_rv_set_pme_wa_enable(struct pp_smu *pp) if (pp_funcs && pp_funcs->notify_smu_enable_pwe) pp_funcs->notify_smu_enable_pwe(pp_handle); - else if (adev->smu.ppt_funcs) - smu_notify_smu_enable_pwe(&adev->smu); } -void pp_rv_set_active_display_count(struct pp_smu *pp, int count) +static void pp_rv_set_active_display_count(struct pp_smu *pp, int count) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -620,7 +611,7 @@ void pp_rv_set_active_display_count(struct pp_smu *pp, int count) pp_funcs->set_active_display_count(pp_handle, count); } -void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) +static void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -633,7 +624,7 @@ void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) pp_funcs->set_min_deep_sleep_dcefclk(pp_handle, clock); } -void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) +static void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -646,7 +637,7 @@ void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) pp_funcs->set_hard_min_dcefclk_by_freq(pp_handle, clock); } -void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) +static void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -670,22 +661,6 @@ static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, return PP_SMU_RESULT_OK; } -enum pp_smu_status pp_nv_set_pme_wa_enable(struct pp_smu *pp) -{ - const struct dc_context *ctx = pp->dm; - struct amdgpu_device *adev = ctx->driver_context; - struct smu_context *smu = &adev->smu; - - if (!smu->ppt_funcs) - return PP_SMU_RESULT_UNSUPPORTED; - - /* 0: successful or smu.ppt_funcs->set_azalia_d3_pme = NULL; 1: fail */ - if (smu_set_azalia_d3_pme(smu)) - return PP_SMU_RESULT_FAIL; - - return PP_SMU_RESULT_OK; -} - static enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) { const struct dc_context *ctx = pp->dm; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 51f57420fadd..d9e33c6bccd9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -33,18 +33,23 @@ #include "amdgpu_dm.h" #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" +#include "amdgpu_dm_trace.h" - - -unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, - unsigned long long current_time_stamp, - unsigned long long last_time_stamp) + unsigned long long + dm_get_elapse_time_in_ns(struct dc_context *ctx, + unsigned long long current_time_stamp, + unsigned long long last_time_stamp) { return current_time_stamp - last_time_stamp; } -void dm_perf_trace_timestamp(const char *func_name, unsigned int line) +void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx) { + trace_amdgpu_dc_performance(ctx->perf_trace->read_count, + ctx->perf_trace->write_count, + &ctx->perf_trace->last_entry_read, + &ctx->perf_trace->last_entry_write, + func_name, line); } /**** power component interfaces ****/ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h index d898981684d5..86960476823c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h @@ -26,45 +26,46 @@ #undef TRACE_SYSTEM #define TRACE_SYSTEM amdgpu_dm -#if !defined(_AMDGPU_DM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#if !defined(_AMDGPU_DM_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) #define _AMDGPU_DM_TRACE_H_ #include <linux/tracepoint.h> +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> +#include <drm/drm_plane.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_encoder.h> +#include <drm/drm_atomic.h> -TRACE_EVENT(amdgpu_dc_rreg, - TP_PROTO(unsigned long *read_count, uint32_t reg, uint32_t value), - TP_ARGS(read_count, reg, value), - TP_STRUCT__entry( - __field(uint32_t, reg) - __field(uint32_t, value) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->value = value; - *read_count = *read_count + 1; - ), - TP_printk("reg=0x%08lx, value=0x%08lx", - (unsigned long)__entry->reg, - (unsigned long)__entry->value) -); +#include "dc/inc/core_types.h" -TRACE_EVENT(amdgpu_dc_wreg, - TP_PROTO(unsigned long *write_count, uint32_t reg, uint32_t value), - TP_ARGS(write_count, reg, value), - TP_STRUCT__entry( - __field(uint32_t, reg) - __field(uint32_t, value) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->value = value; - *write_count = *write_count + 1; - ), - TP_printk("reg=0x%08lx, value=0x%08lx", - (unsigned long)__entry->reg, - (unsigned long)__entry->value) +DECLARE_EVENT_CLASS(amdgpu_dc_reg_template, + TP_PROTO(unsigned long *count, uint32_t reg, uint32_t value), + TP_ARGS(count, reg, value), + + TP_STRUCT__entry( + __field(uint32_t, reg) + __field(uint32_t, value) + ), + + TP_fast_assign( + __entry->reg = reg; + __entry->value = value; + *count = *count + 1; + ), + + TP_printk("reg=0x%08lx, value=0x%08lx", + (unsigned long)__entry->reg, + (unsigned long)__entry->value) ); +DEFINE_EVENT(amdgpu_dc_reg_template, amdgpu_dc_rreg, + TP_PROTO(unsigned long *count, uint32_t reg, uint32_t value), + TP_ARGS(count, reg, value)); + +DEFINE_EVENT(amdgpu_dc_reg_template, amdgpu_dc_wreg, + TP_PROTO(unsigned long *count, uint32_t reg, uint32_t value), + TP_ARGS(count, reg, value)); TRACE_EVENT(amdgpu_dc_performance, TP_PROTO(unsigned long read_count, unsigned long write_count, @@ -96,6 +97,506 @@ TRACE_EVENT(amdgpu_dc_performance, (unsigned long)__entry->write_delta, (unsigned long)__entry->writes) ); + +TRACE_EVENT(amdgpu_dm_connector_atomic_check, + TP_PROTO(const struct drm_connector_state *state), + TP_ARGS(state), + + TP_STRUCT__entry( + __field(uint32_t, conn_id) + __field(const struct drm_connector_state *, conn_state) + __field(const struct drm_atomic_state *, state) + __field(const struct drm_crtc_commit *, commit) + __field(uint32_t, crtc_id) + __field(uint32_t, best_encoder_id) + __field(enum drm_link_status, link_status) + __field(bool, self_refresh_aware) + __field(enum hdmi_picture_aspect, picture_aspect_ratio) + __field(unsigned int, content_type) + __field(unsigned int, hdcp_content_type) + __field(unsigned int, content_protection) + __field(unsigned int, scaling_mode) + __field(u32, colorspace) + __field(u8, max_requested_bpc) + __field(u8, max_bpc) + ), + + TP_fast_assign( + __entry->conn_id = state->connector->base.id; + __entry->conn_state = state; + __entry->state = state->state; + __entry->commit = state->commit; + __entry->crtc_id = state->crtc ? state->crtc->base.id : 0; + __entry->best_encoder_id = state->best_encoder ? + state->best_encoder->base.id : 0; + __entry->link_status = state->link_status; + __entry->self_refresh_aware = state->self_refresh_aware; + __entry->picture_aspect_ratio = state->picture_aspect_ratio; + __entry->content_type = state->content_type; + __entry->hdcp_content_type = state->hdcp_content_type; + __entry->content_protection = state->content_protection; + __entry->scaling_mode = state->scaling_mode; + __entry->colorspace = state->colorspace; + __entry->max_requested_bpc = state->max_requested_bpc; + __entry->max_bpc = state->max_bpc; + ), + + TP_printk("conn_id=%u conn_state=%p state=%p commit=%p crtc_id=%u " + "best_encoder_id=%u link_status=%d self_refresh_aware=%d " + "picture_aspect_ratio=%d content_type=%u " + "hdcp_content_type=%u content_protection=%u scaling_mode=%u " + "colorspace=%u max_requested_bpc=%u max_bpc=%u", + __entry->conn_id, __entry->conn_state, __entry->state, + __entry->commit, __entry->crtc_id, __entry->best_encoder_id, + __entry->link_status, __entry->self_refresh_aware, + __entry->picture_aspect_ratio, __entry->content_type, + __entry->hdcp_content_type, __entry->content_protection, + __entry->scaling_mode, __entry->colorspace, + __entry->max_requested_bpc, __entry->max_bpc) +); + +TRACE_EVENT(amdgpu_dm_crtc_atomic_check, + TP_PROTO(const struct drm_crtc_state *state), + TP_ARGS(state), + + TP_STRUCT__entry( + __field(const struct drm_atomic_state *, state) + __field(const struct drm_crtc_state *, crtc_state) + __field(const struct drm_crtc_commit *, commit) + __field(uint32_t, crtc_id) + __field(bool, enable) + __field(bool, active) + __field(bool, planes_changed) + __field(bool, mode_changed) + __field(bool, active_changed) + __field(bool, connectors_changed) + __field(bool, zpos_changed) + __field(bool, color_mgmt_changed) + __field(bool, no_vblank) + __field(bool, async_flip) + __field(bool, vrr_enabled) + __field(bool, self_refresh_active) + __field(u32, plane_mask) + __field(u32, connector_mask) + __field(u32, encoder_mask) + ), + + TP_fast_assign( + __entry->state = state->state; + __entry->crtc_state = state; + __entry->crtc_id = state->crtc->base.id; + __entry->commit = state->commit; + __entry->enable = state->enable; + __entry->active = state->active; + __entry->planes_changed = state->planes_changed; + __entry->mode_changed = state->mode_changed; + __entry->active_changed = state->active_changed; + __entry->connectors_changed = state->connectors_changed; + __entry->zpos_changed = state->zpos_changed; + __entry->color_mgmt_changed = state->color_mgmt_changed; + __entry->no_vblank = state->no_vblank; + __entry->async_flip = state->async_flip; + __entry->vrr_enabled = state->vrr_enabled; + __entry->self_refresh_active = state->self_refresh_active; + __entry->plane_mask = state->plane_mask; + __entry->connector_mask = state->connector_mask; + __entry->encoder_mask = state->encoder_mask; + ), + + TP_printk("crtc_id=%u crtc_state=%p state=%p commit=%p changed(" + "planes=%d mode=%d active=%d conn=%d zpos=%d color_mgmt=%d) " + "state(enable=%d active=%d async_flip=%d vrr_enabled=%d " + "self_refresh_active=%d no_vblank=%d) mask(plane=%x conn=%x " + "enc=%x)", + __entry->crtc_id, __entry->crtc_state, __entry->state, + __entry->commit, __entry->planes_changed, + __entry->mode_changed, __entry->active_changed, + __entry->connectors_changed, __entry->zpos_changed, + __entry->color_mgmt_changed, __entry->enable, __entry->active, + __entry->async_flip, __entry->vrr_enabled, + __entry->self_refresh_active, __entry->no_vblank, + __entry->plane_mask, __entry->connector_mask, + __entry->encoder_mask) +); + +DECLARE_EVENT_CLASS(amdgpu_dm_plane_state_template, + TP_PROTO(const struct drm_plane_state *state), + TP_ARGS(state), + TP_STRUCT__entry( + __field(uint32_t, plane_id) + __field(enum drm_plane_type, plane_type) + __field(const struct drm_plane_state *, plane_state) + __field(const struct drm_atomic_state *, state) + __field(uint32_t, crtc_id) + __field(uint32_t, fb_id) + __field(uint32_t, fb_format) + __field(uint8_t, fb_planes) + __field(uint64_t, fb_modifier) + __field(const struct dma_fence *, fence) + __field(int32_t, crtc_x) + __field(int32_t, crtc_y) + __field(uint32_t, crtc_w) + __field(uint32_t, crtc_h) + __field(uint32_t, src_x) + __field(uint32_t, src_y) + __field(uint32_t, src_w) + __field(uint32_t, src_h) + __field(u32, alpha) + __field(uint32_t, pixel_blend_mode) + __field(unsigned int, rotation) + __field(unsigned int, zpos) + __field(unsigned int, normalized_zpos) + __field(enum drm_color_encoding, color_encoding) + __field(enum drm_color_range, color_range) + __field(bool, visible) + ), + + TP_fast_assign( + __entry->plane_id = state->plane->base.id; + __entry->plane_type = state->plane->type; + __entry->plane_state = state; + __entry->state = state->state; + __entry->crtc_id = state->crtc ? state->crtc->base.id : 0; + __entry->fb_id = state->fb ? state->fb->base.id : 0; + __entry->fb_format = state->fb ? state->fb->format->format : 0; + __entry->fb_planes = state->fb ? state->fb->format->num_planes : 0; + __entry->fb_modifier = state->fb ? state->fb->modifier : 0; + __entry->fence = state->fence; + __entry->crtc_x = state->crtc_x; + __entry->crtc_y = state->crtc_y; + __entry->crtc_w = state->crtc_w; + __entry->crtc_h = state->crtc_h; + __entry->src_x = state->src_x >> 16; + __entry->src_y = state->src_y >> 16; + __entry->src_w = state->src_w >> 16; + __entry->src_h = state->src_h >> 16; + __entry->alpha = state->alpha; + __entry->pixel_blend_mode = state->pixel_blend_mode; + __entry->rotation = state->rotation; + __entry->zpos = state->zpos; + __entry->normalized_zpos = state->normalized_zpos; + __entry->color_encoding = state->color_encoding; + __entry->color_range = state->color_range; + __entry->visible = state->visible; + ), + + TP_printk("plane_id=%u plane_type=%d plane_state=%p state=%p " + "crtc_id=%u fb(id=%u fmt=%c%c%c%c planes=%u mod=%llu) " + "fence=%p crtc_x=%d crtc_y=%d crtc_w=%u crtc_h=%u " + "src_x=%u src_y=%u src_w=%u src_h=%u alpha=%u " + "pixel_blend_mode=%u rotation=%u zpos=%u " + "normalized_zpos=%u color_encoding=%d color_range=%d " + "visible=%d", + __entry->plane_id, __entry->plane_type, __entry->plane_state, + __entry->state, __entry->crtc_id, __entry->fb_id, + (__entry->fb_format & 0xff) ? (__entry->fb_format & 0xff) : 'N', + ((__entry->fb_format >> 8) & 0xff) ? ((__entry->fb_format >> 8) & 0xff) : 'O', + ((__entry->fb_format >> 16) & 0xff) ? ((__entry->fb_format >> 16) & 0xff) : 'N', + ((__entry->fb_format >> 24) & 0x7f) ? ((__entry->fb_format >> 24) & 0x7f) : 'E', + __entry->fb_planes, + __entry->fb_modifier, __entry->fence, __entry->crtc_x, + __entry->crtc_y, __entry->crtc_w, __entry->crtc_h, + __entry->src_x, __entry->src_y, __entry->src_w, __entry->src_h, + __entry->alpha, __entry->pixel_blend_mode, __entry->rotation, + __entry->zpos, __entry->normalized_zpos, + __entry->color_encoding, __entry->color_range, + __entry->visible) +); + +DEFINE_EVENT(amdgpu_dm_plane_state_template, amdgpu_dm_plane_atomic_check, + TP_PROTO(const struct drm_plane_state *state), + TP_ARGS(state)); + +DEFINE_EVENT(amdgpu_dm_plane_state_template, amdgpu_dm_atomic_update_cursor, + TP_PROTO(const struct drm_plane_state *state), + TP_ARGS(state)); + +TRACE_EVENT(amdgpu_dm_atomic_state_template, + TP_PROTO(const struct drm_atomic_state *state), + TP_ARGS(state), + + TP_STRUCT__entry( + __field(const struct drm_atomic_state *, state) + __field(bool, allow_modeset) + __field(bool, legacy_cursor_update) + __field(bool, async_update) + __field(bool, duplicated) + __field(int, num_connector) + __field(int, num_private_objs) + ), + + TP_fast_assign( + __entry->state = state; + __entry->allow_modeset = state->allow_modeset; + __entry->legacy_cursor_update = state->legacy_cursor_update; + __entry->async_update = state->async_update; + __entry->duplicated = state->duplicated; + __entry->num_connector = state->num_connector; + __entry->num_private_objs = state->num_private_objs; + ), + + TP_printk("state=%p allow_modeset=%d legacy_cursor_update=%d " + "async_update=%d duplicated=%d num_connector=%d " + "num_private_objs=%d", + __entry->state, __entry->allow_modeset, __entry->legacy_cursor_update, + __entry->async_update, __entry->duplicated, __entry->num_connector, + __entry->num_private_objs) +); + +DEFINE_EVENT(amdgpu_dm_atomic_state_template, amdgpu_dm_atomic_commit_tail_begin, + TP_PROTO(const struct drm_atomic_state *state), + TP_ARGS(state)); + +DEFINE_EVENT(amdgpu_dm_atomic_state_template, amdgpu_dm_atomic_commit_tail_finish, + TP_PROTO(const struct drm_atomic_state *state), + TP_ARGS(state)); + +DEFINE_EVENT(amdgpu_dm_atomic_state_template, amdgpu_dm_atomic_check_begin, + TP_PROTO(const struct drm_atomic_state *state), + TP_ARGS(state)); + +TRACE_EVENT(amdgpu_dm_atomic_check_finish, + TP_PROTO(const struct drm_atomic_state *state, int res), + TP_ARGS(state, res), + + TP_STRUCT__entry( + __field(const struct drm_atomic_state *, state) + __field(int, res) + __field(bool, async_update) + __field(bool, allow_modeset) + ), + + TP_fast_assign( + __entry->state = state; + __entry->res = res; + __entry->async_update = state->async_update; + __entry->allow_modeset = state->allow_modeset; + ), + + TP_printk("state=%p res=%d async_update=%d allow_modeset=%d", + __entry->state, __entry->res, + __entry->async_update, __entry->allow_modeset) +); + +TRACE_EVENT(amdgpu_dm_dc_pipe_state, + TP_PROTO(int pipe_idx, const struct dc_plane_state *plane_state, + const struct dc_stream_state *stream, + const struct plane_resource *plane_res, + int update_flags), + TP_ARGS(pipe_idx, plane_state, stream, plane_res, update_flags), + + TP_STRUCT__entry( + __field(int, pipe_idx) + __field(const void *, stream) + __field(int, stream_w) + __field(int, stream_h) + __field(int, dst_x) + __field(int, dst_y) + __field(int, dst_w) + __field(int, dst_h) + __field(int, src_x) + __field(int, src_y) + __field(int, src_w) + __field(int, src_h) + __field(int, clip_x) + __field(int, clip_y) + __field(int, clip_w) + __field(int, clip_h) + __field(int, recout_x) + __field(int, recout_y) + __field(int, recout_w) + __field(int, recout_h) + __field(int, viewport_x) + __field(int, viewport_y) + __field(int, viewport_w) + __field(int, viewport_h) + __field(int, flip_immediate) + __field(int, surface_pitch) + __field(int, format) + __field(int, swizzle) + __field(unsigned int, update_flags) + ), + + TP_fast_assign( + __entry->pipe_idx = pipe_idx; + __entry->stream = stream; + __entry->stream_w = stream->timing.h_addressable; + __entry->stream_h = stream->timing.v_addressable; + __entry->dst_x = plane_state->dst_rect.x; + __entry->dst_y = plane_state->dst_rect.y; + __entry->dst_w = plane_state->dst_rect.width; + __entry->dst_h = plane_state->dst_rect.height; + __entry->src_x = plane_state->src_rect.x; + __entry->src_y = plane_state->src_rect.y; + __entry->src_w = plane_state->src_rect.width; + __entry->src_h = plane_state->src_rect.height; + __entry->clip_x = plane_state->clip_rect.x; + __entry->clip_y = plane_state->clip_rect.y; + __entry->clip_w = plane_state->clip_rect.width; + __entry->clip_h = plane_state->clip_rect.height; + __entry->recout_x = plane_res->scl_data.recout.x; + __entry->recout_y = plane_res->scl_data.recout.y; + __entry->recout_w = plane_res->scl_data.recout.width; + __entry->recout_h = plane_res->scl_data.recout.height; + __entry->viewport_x = plane_res->scl_data.viewport.x; + __entry->viewport_y = plane_res->scl_data.viewport.y; + __entry->viewport_w = plane_res->scl_data.viewport.width; + __entry->viewport_h = plane_res->scl_data.viewport.height; + __entry->flip_immediate = plane_state->flip_immediate; + __entry->surface_pitch = plane_state->plane_size.surface_pitch; + __entry->format = plane_state->format; + __entry->swizzle = plane_state->tiling_info.gfx9.swizzle; + __entry->update_flags = update_flags; + ), + TP_printk("pipe_idx=%d stream=%p rct(%d,%d) dst=(%d,%d,%d,%d) " + "src=(%d,%d,%d,%d) clip=(%d,%d,%d,%d) recout=(%d,%d,%d,%d) " + "viewport=(%d,%d,%d,%d) flip_immediate=%d pitch=%d " + "format=%d swizzle=%d update_flags=%x", + __entry->pipe_idx, + __entry->stream, + __entry->stream_w, + __entry->stream_h, + __entry->dst_x, + __entry->dst_y, + __entry->dst_w, + __entry->dst_h, + __entry->src_x, + __entry->src_y, + __entry->src_w, + __entry->src_h, + __entry->clip_x, + __entry->clip_y, + __entry->clip_w, + __entry->clip_h, + __entry->recout_x, + __entry->recout_y, + __entry->recout_w, + __entry->recout_h, + __entry->viewport_x, + __entry->viewport_y, + __entry->viewport_w, + __entry->viewport_h, + __entry->flip_immediate, + __entry->surface_pitch, + __entry->format, + __entry->swizzle, + __entry->update_flags + ) +); + +TRACE_EVENT(amdgpu_dm_dc_clocks_state, + TP_PROTO(const struct dc_clocks *clk), + TP_ARGS(clk), + + TP_STRUCT__entry( + __field(int, dispclk_khz) + __field(int, dppclk_khz) + __field(int, disp_dpp_voltage_level_khz) + __field(int, dcfclk_khz) + __field(int, socclk_khz) + __field(int, dcfclk_deep_sleep_khz) + __field(int, fclk_khz) + __field(int, phyclk_khz) + __field(int, dramclk_khz) + __field(int, p_state_change_support) + __field(int, prev_p_state_change_support) + __field(int, pwr_state) + __field(int, dtm_level) + __field(int, max_supported_dppclk_khz) + __field(int, max_supported_dispclk_khz) + __field(int, bw_dppclk_khz) + __field(int, bw_dispclk_khz) + ), + TP_fast_assign( + __entry->dispclk_khz = clk->dispclk_khz; + __entry->dppclk_khz = clk->dppclk_khz; + __entry->dcfclk_khz = clk->dcfclk_khz; + __entry->socclk_khz = clk->socclk_khz; + __entry->dcfclk_deep_sleep_khz = clk->dcfclk_deep_sleep_khz; + __entry->fclk_khz = clk->fclk_khz; + __entry->phyclk_khz = clk->phyclk_khz; + __entry->dramclk_khz = clk->dramclk_khz; + __entry->p_state_change_support = clk->p_state_change_support; + __entry->prev_p_state_change_support = clk->prev_p_state_change_support; + __entry->pwr_state = clk->pwr_state; + __entry->prev_p_state_change_support = clk->prev_p_state_change_support; + __entry->dtm_level = clk->dtm_level; + __entry->max_supported_dppclk_khz = clk->max_supported_dppclk_khz; + __entry->max_supported_dispclk_khz = clk->max_supported_dispclk_khz; + __entry->bw_dppclk_khz = clk->bw_dppclk_khz; + __entry->bw_dispclk_khz = clk->bw_dispclk_khz; + ), + TP_printk("dispclk_khz=%d dppclk_khz=%d disp_dpp_voltage_level_khz=%d dcfclk_khz=%d socclk_khz=%d " + "dcfclk_deep_sleep_khz=%d fclk_khz=%d phyclk_khz=%d " + "dramclk_khz=%d p_state_change_support=%d " + "prev_p_state_change_support=%d pwr_state=%d prev_p_state_change_support=%d " + "dtm_level=%d max_supported_dppclk_khz=%d max_supported_dispclk_khz=%d " + "bw_dppclk_khz=%d bw_dispclk_khz=%d ", + __entry->dispclk_khz, + __entry->dppclk_khz, + __entry->disp_dpp_voltage_level_khz, + __entry->dcfclk_khz, + __entry->socclk_khz, + __entry->dcfclk_deep_sleep_khz, + __entry->fclk_khz, + __entry->phyclk_khz, + __entry->dramclk_khz, + __entry->p_state_change_support, + __entry->prev_p_state_change_support, + __entry->pwr_state, + __entry->prev_p_state_change_support, + __entry->dtm_level, + __entry->max_supported_dppclk_khz, + __entry->max_supported_dispclk_khz, + __entry->bw_dppclk_khz, + __entry->bw_dispclk_khz + ) +); + +TRACE_EVENT(amdgpu_dm_dce_clocks_state, + TP_PROTO(const struct dce_bw_output *clk), + TP_ARGS(clk), + + TP_STRUCT__entry( + __field(bool, cpuc_state_change_enable) + __field(bool, cpup_state_change_enable) + __field(bool, stutter_mode_enable) + __field(bool, nbp_state_change_enable) + __field(bool, all_displays_in_sync) + __field(int, sclk_khz) + __field(int, sclk_deep_sleep_khz) + __field(int, yclk_khz) + __field(int, dispclk_khz) + __field(int, blackout_recovery_time_us) + ), + TP_fast_assign( + __entry->cpuc_state_change_enable = clk->cpuc_state_change_enable; + __entry->cpup_state_change_enable = clk->cpup_state_change_enable; + __entry->stutter_mode_enable = clk->stutter_mode_enable; + __entry->nbp_state_change_enable = clk->nbp_state_change_enable; + __entry->all_displays_in_sync = clk->all_displays_in_sync; + __entry->sclk_khz = clk->sclk_khz; + __entry->sclk_deep_sleep_khz = clk->sclk_deep_sleep_khz; + __entry->yclk_khz = clk->yclk_khz; + __entry->dispclk_khz = clk->dispclk_khz; + __entry->blackout_recovery_time_us = clk->blackout_recovery_time_us; + ), + TP_printk("cpuc_state_change_enable=%d cpup_state_change_enable=%d stutter_mode_enable=%d " + "nbp_state_change_enable=%d all_displays_in_sync=%d sclk_khz=%d sclk_deep_sleep_khz=%d " + "yclk_khz=%d dispclk_khz=%d blackout_recovery_time_us=%d", + __entry->cpuc_state_change_enable, + __entry->cpup_state_change_enable, + __entry->stutter_mode_enable, + __entry->nbp_state_change_enable, + __entry->all_displays_in_sync, + __entry->sclk_khz, + __entry->sclk_deep_sleep_khz, + __entry->yclk_khz, + __entry->dispclk_khz, + __entry->blackout_recovery_time_us + ) +); + #endif /* _AMDGPU_DM_TRACE_H_ */ #undef TRACE_INCLUDE_PATH |