diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
194 files changed, 22045 insertions, 1644 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 9a3b7bf8ab0b..91fb72c96545 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -28,7 +28,7 @@ AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o +AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o amdgpu_dm_psr.o endif ifdef CONFIG_DRM_AMD_DC_HDCP 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 515b6d7d9128..b5b5ccf0ed71 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -28,6 +28,7 @@ #include "dm_services_types.h" #include "dc.h" +#include "dc_link_dp.h" #include "dc/inc/core_types.h" #include "dal_asic_id.h" #include "dmub/dmub_srv.h" @@ -57,6 +58,7 @@ #if defined(CONFIG_DEBUG_FS) #include "amdgpu_dm_debugfs.h" #endif +#include "amdgpu_dm_psr.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -108,6 +110,8 @@ MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); #define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB); +#define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB); #define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); @@ -208,12 +212,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, static void handle_cursor_update(struct drm_plane *plane, struct drm_plane_state *old_plane_state); -static void amdgpu_dm_set_psr_caps(struct dc_link *link); -static bool amdgpu_dm_psr_enable(struct dc_stream_state *stream); -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); @@ -314,10 +312,8 @@ get_crtc_by_otg_inst(struct amdgpu_device *adev, struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; - if (otg_inst == -1) { - WARN_ON(1); + if (WARN_ON(otg_inst == -1)) return adev->mode_info.crtcs[0]; - } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { amdgpu_crtc = to_amdgpu_crtc(crtc); @@ -396,8 +392,7 @@ static void dm_pflip_high_irq(void *interrupt_params) e = amdgpu_crtc->event; amdgpu_crtc->event = NULL; - if (!e) - WARN_ON(1); + WARN_ON(!e); vrr_active = amdgpu_dm_vrr_active_irq(amdgpu_crtc); @@ -600,14 +595,14 @@ static void dm_crtc_high_irq(void *interrupt_params) } #if defined(CONFIG_DRM_AMD_DC_DCN) +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) /** * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for * DCN generation ASICs - * @interrupt params - interrupt parameters + * @interrupt_params: interrupt parameters * * Used to set crc window/read out crc value at vertical line 0 position */ -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params) { struct common_irq_params *irq_params = interrupt_params; @@ -981,7 +976,8 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); } - adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); + if (!adev->dm.dc->ctx->dmub_srv) + adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); if (!adev->dm.dc->ctx->dmub_srv) { DRM_ERROR("Couldn't allocate DC DMUB server!\n"); return -ENOMEM; @@ -1147,11 +1143,10 @@ 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: + case CHIP_YELLOW_CARP: init_data.flags.gpu_vm_support = true; break; -#endif default: break; } @@ -1291,6 +1286,15 @@ error: return -EINVAL; } +static int amdgpu_dm_early_fini(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + amdgpu_dm_audio_fini(adev); + + return 0; +} + static void amdgpu_dm_fini(struct amdgpu_device *adev) { int i; @@ -1299,8 +1303,6 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) drm_encoder_cleanup(&adev->dm.mst_encoders[i].base); } - amdgpu_dm_audio_fini(adev); - amdgpu_dm_destroy_drm_device(&adev->dm); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) @@ -1328,10 +1330,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) } #endif - if (adev->dm.dc->ctx->dmub_srv) { - dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); - adev->dm.dc->ctx->dmub_srv = NULL; - } + dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); if (dc_enable_dmub_notifications(adev->dm.dc)) { kfree(adev->dm.dmub_notify); @@ -1404,6 +1403,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case CHIP_DIMGREY_CAVEFISH: case CHIP_BEIGE_GOBY: case CHIP_VANGOGH: + case CHIP_YELLOW_CARP: return 0; case CHIP_NAVI12: fw_name_dmcu = FIRMWARE_NAVI12_DMCU; @@ -1522,6 +1522,10 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) dmub_asic = DMUB_ASIC_DCN303; fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB; break; + case CHIP_YELLOW_CARP: + dmub_asic = DMUB_ASIC_DCN31; + fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; + break; default: /* ASIC doesn't support DMUB. */ @@ -1708,7 +1712,6 @@ static int dm_late_init(void *handle) unsigned int linear_lut[16]; int i; struct dmcu *dmcu = NULL; - bool ret = true; dmcu = adev->dm.dc->res_pool->dmcu; @@ -1725,18 +1728,23 @@ static int dm_late_init(void *handle) * 0xFFFF x 0.01 = 0x28F */ params.min_abm_backlight = 0x28F; - /* In the case where abm is implemented on dmcub, - * dmcu object will be null. - * ABM 2.4 and up are implemented on dmcub. - */ - if (dmcu) - ret = dmcu_load_iram(dmcu, params); - else if (adev->dm.dc->ctx->dmub_srv) - ret = dmub_init_abm_config(adev->dm.dc->res_pool, params); + * dmcu object will be null. + * ABM 2.4 and up are implemented on dmcub. + */ + if (dmcu) { + if (!dmcu_load_iram(dmcu, params)) + return -EINVAL; + } else if (adev->dm.dc->ctx->dmub_srv) { + struct dc_link *edp_links[MAX_NUM_EDP]; + int edp_num; - if (!ret) - return -EINVAL; + get_edp_links(adev->dm.dc, edp_links, &edp_num); + for (i = 0; i < edp_num; i++) { + if (!dmub_init_abm_config(adev->dm.dc->res_pool, params, i)) + return -EINVAL; + } + } return detect_mst_link_for_all_connectors(adev_to_drm(adev)); } @@ -2001,7 +2009,6 @@ static int dm_suspend(void *handle) amdgpu_dm_irq_suspend(adev); - dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3); return 0; @@ -2213,6 +2220,15 @@ static int dm_resume(void *handle) = 0xffffffff; } } +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* + * Resource allocation happens for link encoders for newer ASIC in + * dc_validate_global_state, so we need to revalidate it. + * + * This shouldn't fail (it passed once before), so warn if it does. + */ + WARN_ON(dc_validate_global_state(dm->dc, dc_state, false) != DC_OK); +#endif WARN_ON(!dc_commit_state(dm->dc, dc_state)); @@ -2341,6 +2357,7 @@ static const struct amd_ip_funcs amdgpu_dm_funcs = { .late_init = dm_late_init, .sw_init = dm_sw_init, .sw_fini = dm_sw_fini, + .early_fini = amdgpu_dm_early_fini, .hw_init = dm_hw_init, .hw_fini = dm_hw_fini, .suspend = dm_suspend, @@ -2739,6 +2756,7 @@ static void handle_hpd_rx_irq(void *param) enum dc_connection_type new_connection_type = dc_connection_none; struct amdgpu_device *adev = drm_to_adev(dev); union hpd_irq_data hpd_irq_data; + bool lock_flag = 0; memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); @@ -2768,15 +2786,28 @@ static void handle_hpd_rx_irq(void *param) } } - if (!amdgpu_in_reset(adev)) { + /* + * TODO: We need the lock to avoid touching DC state while it's being + * modified during automated compliance testing, or when link loss + * happens. While this should be split into subhandlers and proper + * interfaces to avoid having to conditionally lock like this in the + * outer layer, we need this workaround temporarily to allow MST + * lightup in some scenarios to avoid timeout. + */ + if (!amdgpu_in_reset(adev) && + (hpd_rx_irq_check_link_loss_status(dc_link, &hpd_irq_data) || + hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST)) { mutex_lock(&adev->dm.dc_lock); + lock_flag = 1; + } + #ifdef CONFIG_DRM_AMD_DC_HDCP result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, NULL); #else result = dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL); #endif + if (!amdgpu_in_reset(adev) && lock_flag) mutex_unlock(&adev->dm.dc_lock); - } out: if (result && !is_mst_root_connector) { @@ -3399,7 +3430,7 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm) if (dm->backlight_caps.caps_valid) return; - amdgpu_acpi_get_backlight_caps(dm->adev, &caps); + amdgpu_acpi_get_backlight_caps(&caps); if (caps.caps_valid) { dm->backlight_caps.caps_valid = true; if (caps.aux_support) @@ -3491,7 +3522,7 @@ static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, rc = dc_link_set_backlight_level_nits(link[i], true, brightness[i], AUX_BL_DEFAULT_TRANSITION_TIME_MS); if (!rc) { - DRM_ERROR("DM: Failed to update backlight via AUX on eDP[%d]\n", i); + DRM_DEBUG("DM: Failed to update backlight via AUX on eDP[%d]\n", i); break; } } @@ -3499,7 +3530,7 @@ static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, for (i = 0; i < dm->num_of_edps; i++) { rc = dc_link_set_backlight_level(dm->backlight_link[i], brightness[i], 0); if (!rc) { - DRM_ERROR("DM: Failed to update backlight on eDP[%d]\n", i); + DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", i); break; } } @@ -3743,6 +3774,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) switch (adev->asic_type) { case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: + case CHIP_YELLOW_CARP: case CHIP_RENOIR: if (register_outbox_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -3847,6 +3879,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case CHIP_DIMGREY_CAVEFISH: case CHIP_BEIGE_GOBY: case CHIP_VANGOGH: + case CHIP_YELLOW_CARP: if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -3868,7 +3901,6 @@ fail: static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm) { - drm_mode_config_cleanup(dm->ddev); drm_atomic_private_obj_fini(&dm->atomic_obj); return; } @@ -4019,6 +4051,11 @@ static int dm_early_init(void *handle) adev->mode_info.num_hpd = 6; adev->mode_info.num_dig = 6; break; + case CHIP_YELLOW_CARP: + adev->mode_info.num_crtc = 4; + adev->mode_info.num_hpd = 4; + adev->mode_info.num_dig = 4; + break; case CHIP_NAVI14: case CHIP_DIMGREY_CAVEFISH: adev->mode_info.num_crtc = 5; @@ -4256,6 +4293,7 @@ fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, adev->asic_type == CHIP_NAVY_FLOUNDER || adev->asic_type == CHIP_DIMGREY_CAVEFISH || adev->asic_type == CHIP_BEIGE_GOBY || + adev->asic_type == CHIP_YELLOW_CARP || adev->asic_type == CHIP_VANGOGH) tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; } @@ -4675,6 +4713,7 @@ get_plane_modifiers(const struct amdgpu_device *adev, unsigned int plane_type, u break; case AMDGPU_FAMILY_NV: case AMDGPU_FAMILY_VGH: + case AMDGPU_FAMILY_YC: if (adev->asic_type >= CHIP_SIENNA_CICHLID) add_gfx10_3_modifiers(adev, mods, &size, &capacity); else @@ -4946,6 +4985,14 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev, case DRM_FORMAT_ABGR16161616F: plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F; break; + case DRM_FORMAT_XRGB16161616: + case DRM_FORMAT_ARGB16161616: + plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616; + break; + case DRM_FORMAT_XBGR16161616: + case DRM_FORMAT_ABGR16161616: + plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616; + break; default: DRM_ERROR( "Unsupported screen format %p4cc\n", @@ -5522,6 +5569,93 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context) } } +#if defined(CONFIG_DRM_AMD_DC_DCN) +static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, + struct dc_sink *sink, struct dc_stream_state *stream, + struct dsc_dec_dpcd_caps *dsc_caps) +{ + stream->timing.flags.DSC = 0; + + if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { + dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, + 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); + } +} + +static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, + struct dc_sink *sink, struct dc_stream_state *stream, + struct dsc_dec_dpcd_caps *dsc_caps) +{ + struct drm_connector *drm_connector = &aconnector->base; + uint32_t link_bandwidth_kbps; + + link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, + dc_link_get_link_cap(aconnector->dc_link)); + /* Set DSC policy according to dsc_clock_en */ + dc_dsc_policy_set_enable_dsc_when_not_needed( + aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE); + + if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { + + 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)) { + stream->timing.flags.DSC = 1; + DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n", __func__, drm_connector->name); + } + } + + /* Overwrite the stream flag if DSC is enabled through debugfs */ + if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE) + stream->timing.flags.DSC = 1; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h) + stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v) + stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) + stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; +} +#endif + +/** + * DOC: FreeSync Video + * + * When a userspace application wants to play a video, the content follows a + * standard format definition that usually specifies the FPS for that format. + * The below list illustrates some video format and the expected FPS, + * respectively: + * + * - TV/NTSC (23.976 FPS) + * - Cinema (24 FPS) + * - TV/PAL (25 FPS) + * - TV/NTSC (29.97 FPS) + * - TV/NTSC (30 FPS) + * - Cinema HFR (48 FPS) + * - TV/PAL (50 FPS) + * - Commonly used (60 FPS) + * - Multiples of 24 (48,72,96 FPS) + * + * The list of standards video format is not huge and can be added to the + * connector modeset list beforehand. With that, userspace can leverage + * FreeSync to extends the front porch in order to attain the target refresh + * rate. Such a switch will happen seamlessly, without screen blanking or + * reprogramming of the output in any other way. If the userspace requests a + * modesetting change compatible with FreeSync modes that only differ in the + * refresh rate, DC will skip the full update and avoid blink during the + * transition. For example, the video player can change the modesetting from + * 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without + * causing any display blink. This same concept can be applied to a mode + * setting change. + */ static struct drm_display_mode * get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector, bool use_probed_modes) @@ -5618,12 +5752,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, struct drm_display_mode saved_mode; struct drm_display_mode *freesync_mode = NULL; bool native_mode_found = false; - bool recalculate_timing = dm_state ? (dm_state->scaling != RMX_OFF) : false; + bool recalculate_timing = false; + bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; int mode_refresh; int preferred_refresh = 0; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_dec_dpcd_caps dsc_caps; - uint32_t link_bandwidth_kbps; #endif struct dc_sink *sink = NULL; @@ -5681,7 +5815,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ DRM_DEBUG_DRIVER("No preferred mode found\n"); } else { - recalculate_timing |= amdgpu_freesync_vid_mode && + recalculate_timing = amdgpu_freesync_vid_mode && is_freesync_video_mode(&mode, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); @@ -5689,11 +5823,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, mode = *freesync_mode; } else { decide_crtc_timing_for_drm_display_mode( - &mode, preferred_mode, - dm_state ? (dm_state->scaling != RMX_OFF) : false); - } + &mode, preferred_mode, scale); - preferred_refresh = drm_mode_vrefresh(preferred_mode); + preferred_refresh = drm_mode_vrefresh(preferred_mode); + } } if (recalculate_timing) @@ -5705,7 +5838,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, * If scaling is enabled and refresh rate didn't change * we copy the vic and polarities of the old timings */ - if (!recalculate_timing || mode_refresh != preferred_refresh) + if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode( stream, &mode, &aconnector->base, con_state, NULL, requested_bpc); @@ -5714,45 +5847,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, stream, &mode, &aconnector->base, con_state, old_stream, requested_bpc); - stream->timing.flags.DSC = 0; - - if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { #if defined(CONFIG_DRM_AMD_DC_DCN) - dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, - 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); - link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, - dc_link_get_link_cap(aconnector->dc_link)); - - 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( - aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE); - - 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)) - stream->timing.flags.DSC = 1; - /* Overwrite the stream flag if DSC is enabled through debugfs */ - if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE) - stream->timing.flags.DSC = 1; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h) - stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v) - stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) - stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; - } + /* SST DSC determination policy */ + update_dsc_caps(aconnector, sink, stream, &dsc_caps); + if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) + apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); #endif - } update_stream_scaling_settings(&mode, dm_state, stream); @@ -5780,6 +5880,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, stream->use_vsc_sdp_for_colorimetry = true; } mod_build_vsc_infopacket(stream, &stream->vsc_infopacket); + aconnector->psr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY; + } finish: dc_sink_release(sink); @@ -6551,9 +6653,8 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, dm_update_crtc_active_planes(crtc, crtc_state); - if (unlikely(!dm_crtc_state->stream && - modeset_required(crtc_state, NULL, dm_crtc_state->stream))) { - WARN_ON(1); + if (WARN_ON(unlikely(!dm_crtc_state->stream && + modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) { return ret; } @@ -7052,6 +7153,10 @@ static const uint32_t rgb_formats[] = { DRM_FORMAT_XBGR2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, + DRM_FORMAT_XRGB16161616, + DRM_FORMAT_XBGR16161616, + DRM_FORMAT_ARGB16161616, + DRM_FORMAT_ABGR16161616, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565, @@ -8393,9 +8498,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * deadlock during GPU reset when this fence will not signal * but we hold reservation lock for the BO. */ - r = dma_resv_wait_timeout_rcu(abo->tbo.base.resv, true, - false, - msecs_to_jiffies(5000)); + r = dma_resv_wait_timeout(abo->tbo.base.resv, true, false, + msecs_to_jiffies(5000)); if (unlikely(r <= 0)) DRM_ERROR("Waiting for fences timed out!"); @@ -8591,7 +8695,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, else if ((acrtc_state->update_type == UPDATE_TYPE_FAST) && acrtc_state->stream->link->psr_settings.psr_feature_enabled && !acrtc_state->stream->link->psr_settings.psr_allow_active) { - amdgpu_dm_psr_enable(acrtc_state->stream); + struct amdgpu_dm_connector *aconn = (struct amdgpu_dm_connector *) + acrtc_state->stream->dm_stream_context; + + if (aconn->psr_skip_count > 0) + aconn->psr_skip_count--; + else + amdgpu_dm_psr_enable(acrtc_state->stream); } mutex_unlock(&dm->dc_lock); @@ -8960,7 +9070,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) } status = dc_stream_get_status(dm_new_crtc_state->stream); - WARN_ON(!status); + + if (WARN_ON(!status)) + continue; + WARN_ON(!status->plane_count); /* @@ -9577,7 +9690,8 @@ skip_modeset: BUG_ON(dm_new_crtc_state->stream == NULL); /* Scaling or underscan settings */ - if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state)) + if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) || + drm_atomic_crtc_needs_modeset(new_crtc_state)) update_stream_scaling_settings( &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); @@ -9967,7 +10081,7 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, 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"); + drm_dbg_atomic(crtc->dev, "Cursor plane scaling doesn't match primary plane\n"); return -EINVAL; } @@ -10003,11 +10117,11 @@ static int validate_overlay(struct drm_atomic_state *state) { int i; struct drm_plane *plane; - struct drm_plane_state *old_plane_state, *new_plane_state; - struct drm_plane_state *primary_state, *overlay_state = NULL; + struct drm_plane_state *new_plane_state; + struct drm_plane_state *primary_state, *cursor_state, *overlay_state = NULL; /* Check if primary plane is contained inside overlay */ - for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { + for_each_new_plane_in_state_reverse(state, plane, new_plane_state, i) { if (plane->type == DRM_PLANE_TYPE_OVERLAY) { if (drm_atomic_plane_disabling(plane->state, new_plane_state)) return 0; @@ -10034,6 +10148,14 @@ static int validate_overlay(struct drm_atomic_state *state) if (!primary_state->crtc) return 0; + /* check if cursor plane is enabled */ + cursor_state = drm_atomic_get_plane_state(state, overlay_state->crtc->cursor); + if (IS_ERR(cursor_state)) + return PTR_ERR(cursor_state); + + if (drm_atomic_plane_disabling(plane->state, cursor_state)) + return 0; + /* Perform the bounds check to ensure the overlay plane covers the primary */ if (primary_state->crtc_x < overlay_state->crtc_x || primary_state->crtc_y < overlay_state->crtc_y || @@ -10136,6 +10258,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, dm_old_crtc_state->dsc_force_changed == false) continue; + ret = amdgpu_dm_verify_lut_sizes(new_crtc_state); + if (ret) + goto fail; + if (!new_crtc_state->enable) continue; @@ -10616,136 +10742,6 @@ update: freesync_capable); } -static void amdgpu_dm_set_psr_caps(struct dc_link *link) -{ - uint8_t dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE]; - - if (!(link->connector_signal & SIGNAL_TYPE_EDP)) - return; - if (link->type == dc_connection_none) - return; - if (dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT, - dpcd_data, sizeof(dpcd_data))) { - link->dpcd_caps.psr_caps.psr_version = dpcd_data[0]; - - if (dpcd_data[0] == 0) { - link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; - link->psr_settings.psr_feature_enabled = false; - } else { - link->psr_settings.psr_version = DC_PSR_VERSION_1; - link->psr_settings.psr_feature_enabled = true; - } - - DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled); - } -} - -/* - * amdgpu_dm_link_setup_psr() - configure psr link - * @stream: stream state - * - * Return: true if success - */ -static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream) -{ - struct dc_link *link = NULL; - struct psr_config psr_config = {0}; - struct psr_context psr_context = {0}; - bool ret = false; - - if (stream == NULL) - return false; - - link = stream->link; - - psr_config.psr_version = link->dpcd_caps.psr_caps.psr_version; - - if (psr_config.psr_version > 0) { - psr_config.psr_exit_link_training_required = 0x1; - psr_config.psr_frame_capture_indication_req = 0; - psr_config.psr_rfb_setup_time = 0x37; - psr_config.psr_sdp_transmit_line_num_deadline = 0x20; - psr_config.allow_smu_optimizations = 0x0; - - ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context); - - } - DRM_DEBUG_DRIVER("PSR link: %d\n", link->psr_settings.psr_feature_enabled); - - return ret; -} - -/* - * amdgpu_dm_psr_enable() - enable psr f/w - * @stream: stream state - * - * Return: true if success - */ -bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) -{ - struct dc_link *link = stream->link; - unsigned int vsync_rate_hz = 0; - struct dc_static_screen_params params = {0}; - /* Calculate number of static frames before generating interrupt to - * enter PSR. - */ - // Init fail safe of 2 frames static - unsigned int num_frames_static = 2; - - DRM_DEBUG_DRIVER("Enabling psr...\n"); - - vsync_rate_hz = div64_u64(div64_u64(( - stream->timing.pix_clk_100hz * 100), - stream->timing.v_total), - stream->timing.h_total); - - /* Round up - * Calculate number of frames such that at least 30 ms of time has - * passed. - */ - if (vsync_rate_hz != 0) { - unsigned int frame_time_microsec = 1000000 / vsync_rate_hz; - num_frames_static = (30000 / frame_time_microsec) + 1; - } - - params.triggers.cursor_update = true; - params.triggers.overlay_update = true; - params.triggers.surface_update = true; - params.num_frames = num_frames_static; - - dc_stream_set_static_screen_params(link->ctx->dc, - &stream, 1, - ¶ms); - - return dc_link_set_psr_allow_active(link, true, false, false); -} - -/* - * amdgpu_dm_psr_disable() - disable psr f/w - * @stream: stream state - * - * Return: true if success - */ -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, false); -} - -/* - * amdgpu_dm_psr_disable() - disable psr f/w - * if psr is enabled on any stream - * - * Return: true if success - */ -static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm) -{ - DRM_DEBUG_DRIVER("Disabling psr if psr is enabled on any stream\n"); - return dc_set_psr_allow_active(dm->dc, false); -} - void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) { struct amdgpu_device *adev = drm_to_adev(dev); 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 721c8b49730c..9522d4ca299e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -456,6 +456,7 @@ struct dsc_preferred_settings { uint32_t dsc_num_slices_v; uint32_t dsc_num_slices_h; uint32_t dsc_bits_per_pixel; + bool dsc_force_disable_passthrough; }; struct amdgpu_dm_connector { @@ -508,6 +509,8 @@ struct amdgpu_dm_connector { struct dsc_preferred_settings dsc_settings; /* Cached display modes */ struct drm_display_mode freesync_vid_base; + + int psr_skip_count; }; #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) @@ -616,6 +619,7 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); +int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, struct dc_plane_state *dc_plane_state); 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 157fe4efbb59..a022e5bb30a5 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 @@ -285,6 +285,37 @@ static int __set_input_tf(struct dc_transfer_func *func, } /** + * Verifies that the Degamma and Gamma LUTs attached to the |crtc_state| are of + * the expected size. + * Returns 0 on success. + */ +int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state) +{ + const struct drm_color_lut *lut = NULL; + uint32_t size = 0; + + lut = __extract_blob_lut(crtc_state->degamma_lut, &size); + if (lut && size != MAX_COLOR_LUT_ENTRIES) { + DRM_DEBUG_DRIVER( + "Invalid Degamma LUT size. Should be %u but got %u.\n", + MAX_COLOR_LUT_ENTRIES, size); + return -EINVAL; + } + + lut = __extract_blob_lut(crtc_state->gamma_lut, &size); + if (lut && size != MAX_COLOR_LUT_ENTRIES && + size != MAX_COLOR_LEGACY_LUT_ENTRIES) { + DRM_DEBUG_DRIVER( + "Invalid Gamma LUT size. Should be %u (or %u for legacy) but got %u.\n", + MAX_COLOR_LUT_ENTRIES, MAX_COLOR_LEGACY_LUT_ENTRIES, + size); + return -EINVAL; + } + + return 0; +} + +/** * amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream. * @crtc: amdgpu_dm crtc state * @@ -317,14 +348,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) bool is_legacy; int r; - degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, °amma_size); - if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES) - return -EINVAL; + r = amdgpu_dm_verify_lut_sizes(&crtc->base); + if (r) + return r; + degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, °amma_size); regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, ®amma_size); - if (regamma_lut && regamma_size != MAX_COLOR_LUT_ENTRIES && - regamma_size != MAX_COLOR_LEGACY_LUT_ENTRIES) - return -EINVAL; has_degamma = degamma_lut && !__is_lut_linear(degamma_lut, degamma_size); 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 9fbbd0159119..f1145086a468 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 @@ -887,6 +887,47 @@ unlock: return res; } +/* + * Example usage: + * Disable dsc passthrough, i.e.,: have dsc decoding at converver, not external RX + * echo 1 /sys/kernel/debug/dri/0/DP-1/dsc_disable_passthrough + * Enable dsc passthrough, i.e.,: have dsc passthrough to external RX + * echo 0 /sys/kernel/debug/dri/0/DP-1/dsc_disable_passthrough + */ +static ssize_t dp_dsc_passthrough_set(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + long param; + uint8_t param_nums = 0; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, size, + ¶m, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + aconnector->dsc_settings.dsc_force_disable_passthrough = param; + + kfree(wr_buf); + return 0; +} + #ifdef CONFIG_DRM_AMD_DC_HDCP /* * Returns the HDCP capability of the Display (1.4 for now). @@ -2535,6 +2576,12 @@ static const struct file_operations dp_max_bpc_debugfs_fops = { .llseek = default_llseek }; +static const struct file_operations dp_dsc_disable_passthrough_debugfs_fops = { + .owner = THIS_MODULE, + .write = dp_dsc_passthrough_set, + .llseek = default_llseek +}; + static const struct { char *name; const struct file_operations *fops; @@ -2559,7 +2606,8 @@ static const struct { {"dsc_chunk_size", &dp_dsc_chunk_size_debugfs_fops}, {"dsc_slice_bpg", &dp_dsc_slice_bpg_offset_debugfs_fops}, {"dp_dsc_fec_support", &dp_dsc_fec_support_fops}, - {"max_bpc", &dp_max_bpc_debugfs_fops} + {"max_bpc", &dp_max_bpc_debugfs_fops}, + {"dsc_disable_passthrough", &dp_dsc_disable_passthrough_debugfs_fops}, }; #ifdef CONFIG_DRM_AMD_DC_HDCP diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 666796a0067c..e63c6885c757 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -222,10 +222,23 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, struct amdgpu_dm_connector *aconnector) { struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; + struct drm_connector_state *conn_state = aconnector->base.state; mutex_lock(&hdcp_w->mutex); hdcp_w->aconnector = aconnector; + /* the removal of display will invoke auth reset -> hdcp destroy and + * we'd expect the Content Protection (CP) property changed back to + * DESIRED if at the time ENABLED. CP property change should occur + * before the element removed from linked list. + */ + if (conn_state && conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) { + conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + + DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP 2 -> 1, type %u, DPMS %u\n", + aconnector->base.index, conn_state->hdcp_content_type, aconnector->base.dpms); + } + mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output); process_output(hdcp_w); @@ -454,6 +467,11 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) display->dig_fe = config->dig_fe; link->dig_be = config->dig_be; link->ddc_line = aconnector->dc_link->ddc_hw_inst + 1; + display->stream_enc_idx = config->stream_enc_idx; + link->link_enc_idx = config->link_enc_idx; + link->phy_idx = config->phy_idx; + link->hdcp_supported_informational = dc_link_is_hdcp14(aconnector->dc_link, + aconnector->dc_sink->sink_signal) ? 1 : 0; link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw; link->dp.assr_enabled = config->assr_enabled; link->dp.mst_enabled = config->mst_enabled; @@ -462,7 +480,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) link->adjust.hdcp1.disable = 0; conn_state = aconnector->base.state; - pr_debug("[HDCP_DM] display %d, CP %d, type %d\n", aconnector->base.index, + DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP %d, type %d\n", aconnector->base.index, (!!aconnector->base.state) ? aconnector->base.state->content_protection : -1, (!!aconnector->base.state) ? aconnector->base.state->hdcp_content_type : -1); @@ -637,6 +655,10 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct INIT_DELAYED_WORK(&hdcp_work[i].property_validate_dwork, event_property_validate); hdcp_work[i].hdcp.config.psp.handle = &adev->psp; + if (dc->ctx->dce_version == DCN_VERSION_3_1) { + hdcp_work[i].hdcp.config.psp.caps.dtm_v3_supported = 1; + hdcp_work[i].hdcp.config.psp.caps.opm_state_query_supported = false; + } hdcp_work[i].hdcp.config.ddc.handle = dc_get_link_at_index(dc, i); hdcp_work[i].hdcp.config.ddc.funcs.write_i2c = lp_write_i2c; hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c; 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 4646b0d02939..6fee12c91ef5 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 @@ -655,6 +655,12 @@ void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks) /* TODO: something */ } +void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us) +{ + // TODO: + //amdgpu_device_gpu_recover(dc_context->driver-context, NULL); +} + void *dm_helpers_allocate_gpu_mem( struct dc_context *ctx, enum dc_gpu_mem_alloc_type type, 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 e6b2eec9fb59..5568d4e518e6 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 @@ -160,6 +160,8 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto struct dc_sink *dc_sink = aconnector->dc_sink; struct drm_dp_mst_port *port = aconnector->port; u8 dsc_caps[16] = { 0 }; + u8 dsc_branch_dec_caps_raw[3] = { 0 }; // DSC branch decoder caps 0xA0 ~ 0xA2 + u8 *dsc_branch_dec_caps = NULL; aconnector->dsc_aux = drm_dp_mst_dsc_aux_for_port(port); #if defined(CONFIG_HP_HOOK_WORKAROUND) @@ -182,9 +184,13 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto if (drm_dp_dpcd_read(aconnector->dsc_aux, DP_DSC_SUPPORT, dsc_caps, 16) < 0) return false; + if (drm_dp_dpcd_read(aconnector->dsc_aux, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, dsc_branch_dec_caps_raw, 3) == 3) + dsc_branch_dec_caps = dsc_branch_dec_caps_raw; + if (!dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, - dsc_caps, NULL, - &dc_sink->dsc_caps.dsc_dec_caps)) + dsc_caps, dsc_branch_dec_caps, + &dc_sink->dsc_caps.dsc_dec_caps)) return false; return true; @@ -461,8 +467,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, &aconnector->dm_dp_aux.aux, 16, 4, - (u8)max_link_enc_cap.lane_count, - (u8)max_link_enc_cap.link_rate, + max_link_enc_cap.lane_count, + drm_dp_bw_code_to_link_rate(max_link_enc_cap.link_rate), aconnector->connector_id); drm_connector_attach_dp_subconnector_property(&aconnector->base); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c new file mode 100644 index 000000000000..70a554f1e725 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -0,0 +1,164 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "amdgpu_dm_psr.h" +#include "dc.h" +#include "dm_helpers.h" + +/* + * amdgpu_dm_set_psr_caps() - set link psr capabilities + * @link: link + * + */ +void amdgpu_dm_set_psr_caps(struct dc_link *link) +{ + uint8_t dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE]; + + if (!(link->connector_signal & SIGNAL_TYPE_EDP)) + return; + if (link->type == dc_connection_none) + return; + if (dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT, + dpcd_data, sizeof(dpcd_data))) { + link->dpcd_caps.psr_caps.psr_version = dpcd_data[0]; + + if (dpcd_data[0] == 0) { + link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + link->psr_settings.psr_feature_enabled = false; + } else { + link->psr_settings.psr_version = DC_PSR_VERSION_1; + link->psr_settings.psr_feature_enabled = true; + } + + DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled); + } +} + +/* + * amdgpu_dm_link_setup_psr() - configure psr link + * @stream: stream state + * + * Return: true if success + */ +bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream) +{ + struct dc_link *link = NULL; + struct psr_config psr_config = {0}; + struct psr_context psr_context = {0}; + bool ret = false; + + if (stream == NULL) + return false; + + link = stream->link; + + psr_config.psr_version = link->dpcd_caps.psr_caps.psr_version; + + if (psr_config.psr_version > 0) { + psr_config.psr_exit_link_training_required = 0x1; + psr_config.psr_frame_capture_indication_req = 0; + psr_config.psr_rfb_setup_time = 0x37; + psr_config.psr_sdp_transmit_line_num_deadline = 0x20; + psr_config.allow_smu_optimizations = 0x0; + + ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context); + + } + DRM_DEBUG_DRIVER("PSR link: %d\n", link->psr_settings.psr_feature_enabled); + + return ret; +} + +/* + * amdgpu_dm_psr_enable() - enable psr f/w + * @stream: stream state + * + * Return: true if success + */ +bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) +{ + struct dc_link *link = stream->link; + unsigned int vsync_rate_hz = 0; + struct dc_static_screen_params params = {0}; + /* Calculate number of static frames before generating interrupt to + * enter PSR. + */ + // Init fail safe of 2 frames static + unsigned int num_frames_static = 2; + + DRM_DEBUG_DRIVER("Enabling psr...\n"); + + vsync_rate_hz = div64_u64(div64_u64(( + stream->timing.pix_clk_100hz * 100), + stream->timing.v_total), + stream->timing.h_total); + + /* Round up + * Calculate number of frames such that at least 30 ms of time has + * passed. + */ + if (vsync_rate_hz != 0) { + unsigned int frame_time_microsec = 1000000 / vsync_rate_hz; + num_frames_static = (30000 / frame_time_microsec) + 1; + } + + params.triggers.cursor_update = true; + params.triggers.overlay_update = true; + params.triggers.surface_update = true; + params.num_frames = num_frames_static; + + dc_stream_set_static_screen_params(link->ctx->dc, + &stream, 1, + ¶ms); + + return dc_link_set_psr_allow_active(link, true, false, false); +} + +/* + * amdgpu_dm_psr_disable() - disable psr f/w + * @stream: stream state + * + * Return: true if success + */ +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, false); +} + +/* + * amdgpu_dm_psr_disable() - disable psr f/w + * if psr is enabled on any stream + * + * Return: true if success + */ +bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm) +{ + DRM_DEBUG_DRIVER("Disabling psr if psr is enabled on any stream\n"); + return dc_set_psr_allow_active(dm->dc, false); +} + diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h new file mode 100644 index 000000000000..6806b3c9c84b --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef AMDGPU_DM_AMDGPU_DM_PSR_H_ +#define AMDGPU_DM_AMDGPU_DM_PSR_H_ + +#include "amdgpu.h" + +/* the number of pageflips before enabling psr */ +#define AMDGPU_DM_PSR_ENTRY_DELAY 5 + +void amdgpu_dm_set_psr_caps(struct dc_link *link); +bool amdgpu_dm_psr_enable(struct dc_stream_state *stream); +bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream); +bool amdgpu_dm_psr_disable(struct dc_stream_state *stream); +bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm); + +#endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 505158a5fcc1..943fcb164876 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -34,6 +34,7 @@ DC_LIBS += dcn30 DC_LIBS += dcn301 DC_LIBS += dcn302 DC_LIBS += dcn303 +DC_LIBS += dcn31 endif DC_LIBS += dce120 @@ -57,7 +58,7 @@ include $(AMD_DC) DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \ dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \ -dc_link_enc_cfg.o +dc_link_enc_cfg.o dc_link_dpcd.o ifdef CONFIG_DRM_AMD_DC_DCN DISPLAY_CORE += dc_vm_helper.o diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c67d21a5ee52..9b8ea6e9a2b9 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -979,7 +979,7 @@ static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1( struct spread_spectrum_info *info); /** - * get_ss_info_from_table + * get_ss_info_from_tbl * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or * SS_Info table from the VBIOS * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or @@ -1548,7 +1548,7 @@ static uint32_t get_ss_entry_number_from_ss_info_tbl( uint32_t id); /** - * BiosParserObject::GetNumberofSpreadSpectrumEntry + * bios_parser_get_ss_entry_number * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from * the VBIOS that match the SSid (to be converted from signal) * @@ -1725,7 +1725,7 @@ static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1( return 0; } /** - * get_ss_entry_number_from_internal_ss_info_table_V3_1 + * get_ss_entry_number_from_internal_ss_info_tbl_V3_1 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of * the VBIOS that matches id * diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 49126a0f66af..6dbde74c1e06 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -577,6 +577,11 @@ static struct device_id device_type_from_device_id(uint16_t device_id) result_device_id.enum_id = 1; break; + case ATOM_DISPLAY_LCD2_SUPPORT: + result_device_id.device_type = DEVICE_TYPE_LCD; + result_device_id.enum_id = 2; + break; + case ATOM_DISPLAY_DFP1_SUPPORT: result_device_id.device_type = DEVICE_TYPE_DFP; result_device_id.enum_id = 1; @@ -2133,7 +2138,7 @@ static enum bp_result get_integrated_info_v2_1( info_v2_1->edp1_info.edp_pwr_down_bloff_to_vary_bloff; info->edp1_info.edp_panel_bpc = info_v2_1->edp1_info.edp_panel_bpc; - info->edp1_info.edp_bootup_bl_level = + info->edp1_info.edp_bootup_bl_level = info_v2_1->edp1_info.edp_bootup_bl_level; info->edp2_info.edp_backlight_pwm_hz = le16_to_cpu(info_v2_1->edp2_info.edp_backlight_pwm_hz); @@ -2155,6 +2160,106 @@ static enum bp_result get_integrated_info_v2_1( return BP_RESULT_OK; } +static enum bp_result get_integrated_info_v2_2( + struct bios_parser *bp, + struct integrated_info *info) +{ + struct atom_integrated_system_info_v2_2 *info_v2_2; + uint32_t i; + + info_v2_2 = GET_IMAGE(struct atom_integrated_system_info_v2_2, + DATA_TABLES(integratedsysteminfo)); + + if (info_v2_2 == NULL) + return BP_RESULT_BADBIOSTABLE; + + info->gpu_cap_info = + le32_to_cpu(info_v2_2->gpucapinfo); + /* + * system_config: Bit[0] = 0 : PCIE power gating disabled + * = 1 : PCIE power gating enabled + * Bit[1] = 0 : DDR-PLL shut down disabled + * = 1 : DDR-PLL shut down enabled + * Bit[2] = 0 : DDR-PLL power down disabled + * = 1 : DDR-PLL power down enabled + */ + info->system_config = le32_to_cpu(info_v2_2->system_config); + info->cpu_cap_info = le32_to_cpu(info_v2_2->cpucapinfo); + info->memory_type = info_v2_2->memorytype; + info->ma_channel_number = info_v2_2->umachannelnumber; + info->dp_ss_control = + le16_to_cpu(info_v2_2->reserved1); + + for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) { + info->ext_disp_conn_info.gu_id[i] = + info_v2_2->extdispconninfo.guid[i]; + } + + for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) { + info->ext_disp_conn_info.path[i].device_connector_id = + object_id_from_bios_object_id( + le16_to_cpu(info_v2_2->extdispconninfo.path[i].connectorobjid)); + + info->ext_disp_conn_info.path[i].ext_encoder_obj_id = + object_id_from_bios_object_id( + le16_to_cpu( + info_v2_2->extdispconninfo.path[i].ext_encoder_objid)); + + info->ext_disp_conn_info.path[i].device_tag = + le16_to_cpu( + info_v2_2->extdispconninfo.path[i].device_tag); + info->ext_disp_conn_info.path[i].device_acpi_enum = + le16_to_cpu( + info_v2_2->extdispconninfo.path[i].device_acpi_enum); + info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index = + info_v2_2->extdispconninfo.path[i].auxddclut_index; + info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index = + info_v2_2->extdispconninfo.path[i].hpdlut_index; + info->ext_disp_conn_info.path[i].channel_mapping.raw = + info_v2_2->extdispconninfo.path[i].channelmapping; + info->ext_disp_conn_info.path[i].caps = + le16_to_cpu(info_v2_2->extdispconninfo.path[i].caps); + } + + info->ext_disp_conn_info.checksum = + info_v2_2->extdispconninfo.checksum; + + info->edp1_info.edp_backlight_pwm_hz = + le16_to_cpu(info_v2_2->edp1_info.edp_backlight_pwm_hz); + info->edp1_info.edp_ss_percentage = + le16_to_cpu(info_v2_2->edp1_info.edp_ss_percentage); + info->edp1_info.edp_ss_rate_10hz = + le16_to_cpu(info_v2_2->edp1_info.edp_ss_rate_10hz); + info->edp1_info.edp_pwr_on_off_delay = + info_v2_2->edp1_info.edp_pwr_on_off_delay; + info->edp1_info.edp_pwr_on_vary_bl_to_blon = + info_v2_2->edp1_info.edp_pwr_on_vary_bl_to_blon; + info->edp1_info.edp_pwr_down_bloff_to_vary_bloff = + info_v2_2->edp1_info.edp_pwr_down_bloff_to_vary_bloff; + info->edp1_info.edp_panel_bpc = + info_v2_2->edp1_info.edp_panel_bpc; + info->edp1_info.edp_bootup_bl_level = + + info->edp2_info.edp_backlight_pwm_hz = + le16_to_cpu(info_v2_2->edp2_info.edp_backlight_pwm_hz); + info->edp2_info.edp_ss_percentage = + le16_to_cpu(info_v2_2->edp2_info.edp_ss_percentage); + info->edp2_info.edp_ss_rate_10hz = + le16_to_cpu(info_v2_2->edp2_info.edp_ss_rate_10hz); + info->edp2_info.edp_pwr_on_off_delay = + info_v2_2->edp2_info.edp_pwr_on_off_delay; + info->edp2_info.edp_pwr_on_vary_bl_to_blon = + info_v2_2->edp2_info.edp_pwr_on_vary_bl_to_blon; + info->edp2_info.edp_pwr_down_bloff_to_vary_bloff = + info_v2_2->edp2_info.edp_pwr_down_bloff_to_vary_bloff; + info->edp2_info.edp_panel_bpc = + info_v2_2->edp2_info.edp_panel_bpc; + info->edp2_info.edp_bootup_bl_level = + info_v2_2->edp2_info.edp_bootup_bl_level; + + return BP_RESULT_OK; +} + /* * construct_integrated_info * @@ -2202,6 +2307,9 @@ static enum bp_result construct_integrated_info( case 1: result = get_integrated_info_v2_1(bp, info); break; + case 2: + result = get_integrated_info_v2_2(bp, info); + break; default: return result; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c index 53d7513b5083..adc710fe4a45 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c @@ -82,9 +82,6 @@ void bios_set_scratch_critical_state( uint32_t bios_get_vga_enabled_displays( struct dc_bios *bios) { - uint32_t active_disp = 1; - - active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF; - return active_disp; + return REG_READ(BIOS_SCRATCH_3) & 0XFFFF; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c index 5b77251e0590..e317a3615147 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c @@ -114,7 +114,7 @@ bool dal_cmd_table_helper_controller_id_to_atom( } /** - * translate_transmitter_bp_to_atom - Translate the Transmitter to the + * dal_cmd_table_helper_transmitter_bp_to_atom - Translate the Transmitter to the * corresponding ATOM BIOS value * @t: transmitter * returns: output digitalTransmitter diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 00706b072b5f..cb3fd44cb1ed 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -74,6 +74,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2( case DCN_VERSION_3_01: case DCN_VERSION_3_02: case DCN_VERSION_3_03: + case DCN_VERSION_3_1: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; #endif @@ -129,7 +130,7 @@ bool dal_cmd_table_helper_controller_id_to_atom2( } /** - * translate_transmitter_bp_to_atom2 - Translate the Transmitter to the + * dal_cmd_table_helper_transmitter_bp_to_atom2 - Translate the Transmitter to the * corresponding ATOM BIOS value * @t: transmitter * returns: digitalTransmitter diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 1244fcb0f446..ff5bb152ef49 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -2863,6 +2863,7 @@ static void populate_initial_data( data->bytes_per_pixel[num_displays + 4] = 4; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: data->bytes_per_pixel[num_displays + 4] = 8; break; @@ -2966,6 +2967,7 @@ static void populate_initial_data( data->bytes_per_pixel[num_displays + 4] = 4; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: data->bytes_per_pixel[num_displays + 4] = 8; break; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index d4df4da5b81a..0e18df1283b6 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -236,6 +236,7 @@ static enum dcn_bw_defs tl_pixel_format_to_bw_defs(enum surface_pixel_format for case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: return dcn_bw_rgb_sub_32; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: return dcn_bw_rgb_sub_64; @@ -375,6 +376,7 @@ static void pipe_ctx_to_e2e_pipe_params ( input->src.viewport_height_c = input->src.viewport_height / 2; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: input->src.source_format = dm_444_64; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile index ff96bee57bfc..7fa0b007a7ea 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile @@ -135,4 +135,13 @@ endif AMD_DAL_CLK_MGR_DCN301 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn301/,$(CLK_MGR_DCN301)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN301) + +############################################################################### +# DCN31 +############################################################################### +CLK_MGR_DCN31 = dcn31_smu.o dcn31_clk_mgr.o + +AMD_DAL_CLK_MGR_DCN31 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn31/,$(CLK_MGR_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN31) endif diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index dd52ebf56d62..bb31541f8072 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -41,6 +41,7 @@ #include "dcn21/rn_clk_mgr.h" #include "dcn30/dcn30_clk_mgr.h" #include "dcn301/vg_clk_mgr.h" +#include "dcn31/dcn31_clk_mgr.h" int clk_mgr_helper_get_active_display_cnt( @@ -90,15 +91,20 @@ void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_m struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; int edp_num; + unsigned int panel_inst; get_edp_links(dc, edp_links, &edp_num); if (dc->hwss.exit_optimized_pwr_state) dc->hwss.exit_optimized_pwr_state(dc, dc->current_state); if (edp_num) { - edp_link = edp_links[0]; - clk_mgr->psr_allow_active_cache = edp_link->psr_settings.psr_allow_active; - dc_link_set_psr_allow_active(edp_link, false, false, false); + for (panel_inst = 0; panel_inst < edp_num; panel_inst++) { + edp_link = edp_links[panel_inst]; + if (!edp_link->psr_settings.psr_feature_enabled) + continue; + clk_mgr->psr_allow_active_cache = edp_link->psr_settings.psr_allow_active; + dc_link_set_psr_allow_active(edp_link, false, false, false); + } } } @@ -108,12 +114,17 @@ void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr) struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; int edp_num; + unsigned int panel_inst; get_edp_links(dc, edp_links, &edp_num); if (edp_num) { - edp_link = edp_links[0]; - dc_link_set_psr_allow_active(edp_link, - clk_mgr->psr_allow_active_cache, false, false); + for (panel_inst = 0; panel_inst < edp_num; panel_inst++) { + edp_link = edp_links[panel_inst]; + if (!edp_link->psr_settings.psr_feature_enabled) + continue; + dc_link_set_psr_allow_active(edp_link, + clk_mgr->psr_allow_active_cache, false, false); + } } if (dc->hwss.optimize_pwr_state) @@ -260,7 +271,24 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p return &clk_mgr->base.base; } break; + case FAMILY_YELLOW_CARP: { + struct clk_mgr_dcn31 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL); + + if (clk_mgr == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)) { + /* TODO: to add DCN31 clk_mgr support, once CLK IP header files are available, + * for now use DCN3.0 clk mgr. + */ + dcn31_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); + return &clk_mgr->base.base; + } + return &clk_mgr->base.base; + } #endif + default: ASSERT(0); /* Unknown Asic */ break; @@ -292,6 +320,11 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base) vg_clk_mgr_destroy(clk_mgr); break; + case FAMILY_YELLOW_CARP: + if (ASICREV_IS_YELLOW_CARP(clk_mgr_base->ctx->asic_id.hw_internal_rev)) + dcn31_clk_mgr_destroy(clk_mgr); + break; + default: break; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c index 372d53b5a34d..6e0c5c664fdc 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c @@ -123,7 +123,7 @@ void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, } } -void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr) +void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, struct dc_state *context) { int dpp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dppclk_khz; @@ -132,6 +132,68 @@ void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr) uint32_t dppclk_wdivider = dentist_get_did_from_divider(dpp_divider); uint32_t dispclk_wdivider = dentist_get_did_from_divider(disp_divider); + uint32_t current_dispclk_wdivider; + uint32_t i; + + REG_GET(DENTIST_DISPCLK_CNTL, + DENTIST_DISPCLK_WDIVIDER, ¤t_dispclk_wdivider); + + /* When changing divider to or from 127, some extra programming is required to prevent corruption */ + if (current_dispclk_wdivider == 127 && dispclk_wdivider != 127) { + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + uint32_t fifo_level; + struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + int32_t N; + int32_t j; + + if (!pipe_ctx->stream) + continue; + /* Virtual encoders don't have this function */ + if (!stream_enc->funcs->get_fifo_cal_average_level) + continue; + fifo_level = stream_enc->funcs->get_fifo_cal_average_level( + stream_enc); + N = fifo_level / 4; + dccg->funcs->set_fifo_errdet_ovr_en( + dccg, + true); + for (j = 0; j < N - 4; j++) + dccg->funcs->otg_drop_pixel( + dccg, + pipe_ctx->stream_res.tg->inst); + dccg->funcs->set_fifo_errdet_ovr_en( + dccg, + false); + } + } else if (dispclk_wdivider == 127 && current_dispclk_wdivider != 127) { + REG_UPDATE(DENTIST_DISPCLK_CNTL, + DENTIST_DISPCLK_WDIVIDER, 126); + REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 100); + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + uint32_t fifo_level; + int32_t N; + int32_t j; + + if (!pipe_ctx->stream) + continue; + /* Virtual encoders don't have this function */ + if (!stream_enc->funcs->get_fifo_cal_average_level) + continue; + fifo_level = stream_enc->funcs->get_fifo_cal_average_level( + stream_enc); + N = fifo_level / 4; + dccg->funcs->set_fifo_errdet_ovr_en(dccg, true); + for (j = 0; j < 12 - N; j++) + dccg->funcs->otg_add_pixel(dccg, + pipe_ctx->stream_res.tg->inst); + dccg->funcs->set_fifo_errdet_ovr_en(dccg, false); + } + } REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider); @@ -251,11 +313,11 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, if (dpp_clock_lowered) { // if clock is being lowered, increase DTO before lowering refclk dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); - dcn20_update_clocks_update_dentist(clk_mgr); + dcn20_update_clocks_update_dentist(clk_mgr, context); } else { // if clock is being raised, increase refclk before lowering DTO if (update_dppclk || update_dispclk) - dcn20_update_clocks_update_dentist(clk_mgr); + dcn20_update_clocks_update_dentist(clk_mgr, context); // always update dtos unless clock is lowered and not safe to lower dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); } @@ -324,6 +386,8 @@ void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr, // Both fclk and ref_dppclk run on the same scemi clock. clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz; + /* TODO: set dtbclk in correct place */ + clk_mgr->clks.dtbclk_en = false; dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks); } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h index 0b9c045b0c8e..d254d0b6fba1 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h @@ -50,7 +50,8 @@ void dcn2_get_clock(struct clk_mgr *clk_mgr, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg); -void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr); +void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, + struct dc_state *context); void dcn2_read_clocks_from_hw_dentist(struct clk_mgr *clk_mgr_base); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c index 416a24db17a9..c6f494f0dcea 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -835,66 +835,47 @@ static struct wm_table lpddr4_wm_table_rn = { } }; -static unsigned int find_max_fclk_for_voltage(struct dpm_clocks *clock_table, - unsigned int voltage) +static unsigned int find_socclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage) { int i; - uint32_t max_clk = 0; - for (i = 0; i < PP_SMU_NUM_FCLK_DPM_LEVELS; i++) { - if (clock_table->FClocks[i].Vol <= voltage) { - max_clk = clock_table->FClocks[i].Freq > max_clk ? - clock_table->FClocks[i].Freq : max_clk; - } - } - - return max_clk; -} - -static unsigned int find_max_memclk_for_voltage(struct dpm_clocks *clock_table, - unsigned int voltage) -{ - int i; - uint32_t max_clk = 0; - - for (i = 0; i < PP_SMU_NUM_MEMCLK_DPM_LEVELS; i++) { - if (clock_table->MemClocks[i].Vol <= voltage) { - max_clk = clock_table->MemClocks[i].Freq > max_clk ? - clock_table->MemClocks[i].Freq : max_clk; - } + for (i = 0; i < PP_SMU_NUM_SOCCLK_DPM_LEVELS; i++) { + if (clock_table->SocClocks[i].Vol == voltage) + return clock_table->SocClocks[i].Freq; } - return max_clk; + ASSERT(0); + return 0; } -static unsigned int find_max_socclk_for_voltage(struct dpm_clocks *clock_table, - unsigned int voltage) +static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage) { int i; - uint32_t max_clk = 0; - for (i = 0; i < PP_SMU_NUM_SOCCLK_DPM_LEVELS; i++) { - if (clock_table->SocClocks[i].Vol <= voltage) { - max_clk = clock_table->SocClocks[i].Freq > max_clk ? - clock_table->SocClocks[i].Freq : max_clk; - } + for (i = 0; i < PP_SMU_NUM_DCFCLK_DPM_LEVELS; i++) { + if (clock_table->DcfClocks[i].Vol == voltage) + return clock_table->DcfClocks[i].Freq; } - return max_clk; + ASSERT(0); + return 0; } static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params, struct dpm_clocks *clock_table, struct integrated_info *bios_info) { int i, j = 0; - unsigned int volt; j = -1; - /* Find max DPM */ - for (i = 0; i < PP_SMU_NUM_DCFCLK_DPM_LEVELS; ++i) { - if (clock_table->DcfClocks[i].Freq != 0 && - clock_table->DcfClocks[i].Vol != 0) + ASSERT(PP_SMU_NUM_FCLK_DPM_LEVELS <= MAX_NUM_DPM_LVL); + + /* Find lowest DPM, FCLK is filled in reverse order*/ + + for (i = PP_SMU_NUM_FCLK_DPM_LEVELS - 1; i >= 0; i--) { + if (clock_table->FClocks[i].Freq != 0 && clock_table->FClocks[i].Vol != 0) { j = i; + break; + } } if (j == -1) { @@ -905,18 +886,13 @@ static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params bw_params->clk_table.num_entries = j + 1; - for (i = 0; i < bw_params->clk_table.num_entries; i++) { - volt = clock_table->DcfClocks[i].Vol; - - bw_params->clk_table.entries[i].voltage = volt; - bw_params->clk_table.entries[i].dcfclk_mhz = - clock_table->DcfClocks[i].Freq; - bw_params->clk_table.entries[i].fclk_mhz = - find_max_fclk_for_voltage(clock_table, volt); - bw_params->clk_table.entries[i].memclk_mhz = - find_max_memclk_for_voltage(clock_table, volt); - bw_params->clk_table.entries[i].socclk_mhz = - find_max_socclk_for_voltage(clock_table, volt); + for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) { + bw_params->clk_table.entries[i].fclk_mhz = clock_table->FClocks[j].Freq; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemClocks[j].Freq; + bw_params->clk_table.entries[i].voltage = clock_table->FClocks[j].Vol; + bw_params->clk_table.entries[i].dcfclk_mhz = find_dcfclk_for_voltage(clock_table, clock_table->FClocks[j].Vol); + bw_params->clk_table.entries[i].socclk_mhz = find_socclk_for_voltage(clock_table, + bw_params->clk_table.entries[i].voltage); } bw_params->vram_type = bios_info->memory_type; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c index 652fa89fae5f..513676a6f52b 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c @@ -334,11 +334,11 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base, if (dpp_clock_lowered) { /* if clock is being lowered, increase DTO before lowering refclk */ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); - dcn20_update_clocks_update_dentist(clk_mgr); + dcn20_update_clocks_update_dentist(clk_mgr, context); } else { /* if clock is being raised, increase refclk before lowering DTO */ if (update_dppclk || update_dispclk) - dcn20_update_clocks_update_dentist(clk_mgr); + dcn20_update_clocks_update_dentist(clk_mgr, context); /* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures * that we do not lower dto when it is not safe to lower. We do not need to * compare the current and new dppclk before calling this function.*/ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c new file mode 100644 index 000000000000..7b7d884d58be --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -0,0 +1,673 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + + +#include "dccg.h" +#include "clk_mgr_internal.h" + +// For dce12_get_dp_ref_freq_khz +#include "dce100/dce_clk_mgr.h" + +// For dcn20_update_clocks_update_dpp_dto +#include "dcn20/dcn20_clk_mgr.h" + + + +#include "dcn31_clk_mgr.h" + +#include "reg_helper.h" +#include "core_types.h" +#include "dcn31_smu.h" +#include "dm_helpers.h" + +/* TODO: remove this include once we ported over remaining clk mgr functions*/ +#include "dcn30/dcn30_clk_mgr.h" + +#include "dc_dmub_srv.h" + +#define TO_CLK_MGR_DCN31(clk_mgr)\ + container_of(clk_mgr, struct clk_mgr_dcn31, base) + +int dcn31_get_active_display_cnt_wa( + struct dc *dc, + struct dc_state *context) +{ + int i, display_count; + bool tmds_present = false; + + display_count = 0; + for (i = 0; i < context->stream_count; i++) { + const struct dc_stream_state *stream = context->streams[i]; + + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || + stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK || + stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) + tmds_present = true; + } + + for (i = 0; i < dc->link_count; i++) { + const struct dc_link *link = dc->links[i]; + + /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) + display_count++; + } + + /* WA for hang on HDMI after display off back back on*/ + if (display_count == 0 && tmds_present) + display_count = 1; + + return display_count; +} + +static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) +{ + struct dc *dc = clk_mgr_base->ctx->dc; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe->top_pipe || pipe->prev_odm_pipe) + continue; + if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { + if (disable) + pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); + } + } +} + +static void dcn31_update_clocks(struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower) +{ + union dmub_rb_cmd cmd; + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; + int display_count; + bool update_dppclk = false; + bool update_dispclk = false; + bool dpp_clock_lowered = false; + + if (dc->work_arounds.skip_clock_update) + return; + + /* + * if it is safe to lower, but we are already in the lower state, we don't have to do anything + * also if safe to lower is false, we just go in the higher state + */ + if (safe_to_lower) { + if (new_clocks->z9_support == DCN_Z9_SUPPORT_ALLOW && + new_clocks->z9_support != clk_mgr_base->clks.z9_support) { + dcn31_smu_set_Z9_support(clk_mgr, true); + clk_mgr_base->clks.z9_support = new_clocks->z9_support; + } + + if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) { + dcn31_smu_set_dtbclk(clk_mgr, false); + clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; + } + /* check that we're not already in lower */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { + display_count = dcn31_get_active_display_cnt_wa(dc, context); + /* if we can go lower, go lower */ + if (display_count == 0) { + union display_idle_optimization_u idle_info = { 0 }; + idle_info.idle_info.df_request_disabled = 1; + idle_info.idle_info.phy_ref_clk_off = 1; + dcn31_smu_set_display_idle_optimization(clk_mgr, idle_info.data); + /* update power state */ + clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; + } + } + } else { + if (new_clocks->z9_support == DCN_Z9_SUPPORT_DISALLOW && + new_clocks->z9_support != clk_mgr_base->clks.z9_support) { + dcn31_smu_set_Z9_support(clk_mgr, false); + clk_mgr_base->clks.z9_support = new_clocks->z9_support; + } + + if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { + dcn31_smu_set_dtbclk(clk_mgr, true); + clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; + } + + /* check that we're not already in D0 */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { + union display_idle_optimization_u idle_info = { 0 }; + dcn31_smu_set_display_idle_optimization(clk_mgr, idle_info.data); + /* update power state */ + clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; + } + } + + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { + clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; + dcn31_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); + } + + if (should_set_clock(safe_to_lower, + new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { + clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + dcn31_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); + } + + // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { + if (new_clocks->dppclk_khz < 100000) + new_clocks->dppclk_khz = 100000; + } + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) + dpp_clock_lowered = true; + clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; + update_dppclk = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { + dcn31_disable_otg_wa(clk_mgr_base, true); + + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; + dcn31_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn31_disable_otg_wa(clk_mgr_base, false); + + update_dispclk = true; + } + + /* TODO: add back DTO programming when DPPCLK restore is fixed in FSDL*/ + if (dpp_clock_lowered) { + // increase per DPP DTO before lowering global dppclk + dcn31_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); + } else { + // increase global DPPCLK before lowering per DPP DTO + if (update_dppclk || update_dispclk) + dcn31_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); + } + + // notify DMCUB of latest clocks + memset(&cmd, 0, sizeof(cmd)); + cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR; + cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS; + cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz; + cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz = + clk_mgr_base->clks.dcfclk_deep_sleep_khz; + cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; + cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; + + dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); + dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); +} + +static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) +{ + return 0; +} + +static void dcn31_enable_pme_wa(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + + dcn31_smu_enable_pme_wa(clk_mgr); +} + +static void dcn31_init_clocks(struct clk_mgr *clk_mgr) +{ + memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); + // Assumption is that boot state always supports pstate + clk_mgr->clks.p_state_change_support = true; + clk_mgr->clks.prev_p_state_change_support = true; + clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; + clk_mgr->clks.z9_support = DCN_Z9_SUPPORT_UNKNOWN; +} + +static bool dcn31_are_clock_states_equal(struct dc_clocks *a, + struct dc_clocks *b) +{ + if (a->dispclk_khz != b->dispclk_khz) + return false; + else if (a->dppclk_khz != b->dppclk_khz) + return false; + else if (a->dcfclk_khz != b->dcfclk_khz) + return false; + else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) + return false; + else if (a->z9_support != b->z9_support) + return false; + else if (a->dtbclk_en != b->dtbclk_en) + return false; + + return true; +} + +static void dcn31_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, + struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) +{ + return; +} + +static struct clk_bw_params dcn31_bw_params = { + .vram_type = Ddr4MemType, + .num_channels = 1, + .clk_table = { + .num_entries = 4, + }, + +}; + +static struct wm_table ddr4_wm_table = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 6.09, + .sr_enter_plus_exit_time_us = 7.14, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, + }, + } +}; + +static struct wm_table lpddr5_wm_table = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 5.32, + .sr_enter_plus_exit_time_us = 6.38, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.82, + .sr_enter_plus_exit_time_us = 11.196, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.89, + .sr_enter_plus_exit_time_us = 11.24, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.748, + .sr_enter_plus_exit_time_us = 11.102, + .valid = true, + }, + } +}; + +static DpmClocks_t dummy_clocks; + +static struct dcn31_watermarks dummy_wms = { 0 }; + +static void dcn31_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn31_watermarks *table) +{ + int i, num_valid_sets; + + num_valid_sets = 0; + + for (i = 0; i < WM_SET_COUNT; i++) { + /* skip empty entries, the smu array has no holes*/ + if (!bw_params->wm_table.entries[i].valid) + continue; + + table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst; + table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type; + /* We will not select WM based on fclk, so leave it as unconstrained */ + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; + + if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) { + if (i == 0) + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0; + else { + /* add 1 to make it non-overlapping with next lvl */ + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = + bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1; + } + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk = + bw_params->clk_table.entries[i].dcfclk_mhz; + + } else { + /* unconstrained for memory retraining */ + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; + table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; + + /* Modify previous watermark range to cover up to max */ + table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; + } + num_valid_sets++; + } + + ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ + + /* modify the min and max to make sure we cover the whole range*/ + table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0; + table->WatermarkRow[WM_DCFCLK][0].MinClock = 0; + table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF; + table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; + + /* This is for writeback only, does not matter currently as no writeback support*/ + table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A; + table->WatermarkRow[WM_SOCCLK][0].MinClock = 0; + table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF; + table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0; + table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF; +} + +static void dcn31_notify_wm_ranges(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct clk_mgr_dcn31 *clk_mgr_dcn31 = TO_CLK_MGR_DCN31(clk_mgr); + struct dcn31_watermarks *table = clk_mgr_dcn31->smu_wm_set.wm_set; + + if (!clk_mgr->smu_ver) + return; + + if (!table || clk_mgr_dcn31->smu_wm_set.mc_address.quad_part == 0) + return; + + memset(table, 0, sizeof(*table)); + + dcn31_build_watermark_ranges(clk_mgr_base->bw_params, table); + + dcn31_smu_set_dram_addr_high(clk_mgr, + clk_mgr_dcn31->smu_wm_set.mc_address.high_part); + dcn31_smu_set_dram_addr_low(clk_mgr, + clk_mgr_dcn31->smu_wm_set.mc_address.low_part); + dcn31_smu_transfer_wm_table_dram_2_smu(clk_mgr); +} + +static void dcn31_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, + struct dcn31_smu_dpm_clks *smu_dpm_clks) +{ + DpmClocks_t *table = smu_dpm_clks->dpm_clks; + + if (!clk_mgr->smu_ver) + return; + + if (!table || smu_dpm_clks->mc_address.quad_part == 0) + return; + + memset(table, 0, sizeof(*table)); + + dcn31_smu_set_dram_addr_high(clk_mgr, + smu_dpm_clks->mc_address.high_part); + dcn31_smu_set_dram_addr_low(clk_mgr, + smu_dpm_clks->mc_address.low_part); + dcn31_smu_transfer_dpm_table_smu_2_dram(clk_mgr); +} + +static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks) +{ + uint32_t max = 0; + int i; + + for (i = 0; i < num_clocks; ++i) { + if (clocks[i] > max) + max = clocks[i]; + } + + return max; +} + +static unsigned int find_clk_for_voltage( + const DpmClocks_t *clock_table, + const uint32_t clocks[], + unsigned int voltage) +{ + int i; + + for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) { + if (clock_table->SocVoltage[i] == voltage) + return clocks[i]; + } + + ASSERT(0); + return 0; +} + +void dcn31_clk_mgr_helper_populate_bw_params( + struct clk_mgr_internal *clk_mgr, + struct integrated_info *bios_info, + const DpmClocks_t *clock_table) +{ + int i, j; + struct clk_bw_params *bw_params = clk_mgr->base.bw_params; + uint32_t max_dispclk = 0, max_dppclk = 0; + + j = -1; + + ASSERT(NUM_DF_PSTATE_LEVELS <= MAX_NUM_DPM_LVL); + + /* Find lowest DPM, FCLK is filled in reverse order*/ + + for (i = NUM_DF_PSTATE_LEVELS - 1; i >= 0; i--) { + if (clock_table->DfPstateTable[i].FClk != 0) { + j = i; + break; + } + } + + if (j == -1) { + /* clock table is all 0s, just use our own hardcode */ + ASSERT(0); + return; + } + + bw_params->clk_table.num_entries = j + 1; + + /* dispclk and dppclk can be max at any voltage, same number of levels for both */ + if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS && + clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) { + max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled); + max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled); + } else { + ASSERT(0); + } + + for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) { + bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[j].FClk; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[j].MemClk; + bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[j].Voltage; + switch (clock_table->DfPstateTable[j].WckRatio) { + case WCK_RATIO_1_2: + bw_params->clk_table.entries[i].wck_ratio = 2; + break; + case WCK_RATIO_1_4: + bw_params->clk_table.entries[i].wck_ratio = 4; + break; + default: + bw_params->clk_table.entries[i].wck_ratio = 1; + } + bw_params->clk_table.entries[i].dcfclk_mhz = find_clk_for_voltage(clock_table, clock_table->DcfClocks, clock_table->DfPstateTable[j].Voltage); + bw_params->clk_table.entries[i].socclk_mhz = find_clk_for_voltage(clock_table, clock_table->SocClocks, clock_table->DfPstateTable[j].Voltage); + bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; + bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; + } + + bw_params->vram_type = bios_info->memory_type; + bw_params->num_channels = bios_info->ma_channel_number; + + for (i = 0; i < WM_SET_COUNT; i++) { + bw_params->wm_table.entries[i].wm_inst = i; + + if (i >= bw_params->clk_table.num_entries) { + bw_params->wm_table.entries[i].valid = false; + continue; + } + + bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; + bw_params->wm_table.entries[i].valid = true; + } +} + +static struct clk_mgr_funcs dcn31_funcs = { + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .update_clocks = dcn31_update_clocks, + .init_clocks = dcn31_init_clocks, + .enable_pme_wa = dcn31_enable_pme_wa, + .are_clock_states_equal = dcn31_are_clock_states_equal, + .notify_wm_ranges = dcn31_notify_wm_ranges +}; +extern struct clk_mgr_funcs dcn3_fpga_funcs; + +void dcn31_clk_mgr_construct( + struct dc_context *ctx, + struct clk_mgr_dcn31 *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg) +{ + struct dcn31_smu_dpm_clks smu_dpm_clks = { 0 }; + + clk_mgr->base.base.ctx = ctx; + clk_mgr->base.base.funcs = &dcn31_funcs; + + clk_mgr->base.pp_smu = pp_smu; + + clk_mgr->base.dccg = dccg; + clk_mgr->base.dfs_bypass_disp_clk = 0; + + clk_mgr->base.dprefclk_ss_percentage = 0; + clk_mgr->base.dprefclk_ss_divider = 1000; + clk_mgr->base.ss_on_dprefclk = false; + + clk_mgr->smu_wm_set.wm_set = (struct dcn31_watermarks *)dm_helpers_allocate_gpu_mem( + clk_mgr->base.base.ctx, + DC_MEM_ALLOC_TYPE_FRAME_BUFFER, + sizeof(struct dcn31_watermarks), + &clk_mgr->smu_wm_set.mc_address.quad_part); + + if (clk_mgr->smu_wm_set.wm_set == 0) { + clk_mgr->smu_wm_set.wm_set = &dummy_wms; + clk_mgr->smu_wm_set.mc_address.quad_part = 0; + } + ASSERT(clk_mgr->smu_wm_set.wm_set); + + smu_dpm_clks.dpm_clks = (DpmClocks_t *)dm_helpers_allocate_gpu_mem( + clk_mgr->base.base.ctx, + DC_MEM_ALLOC_TYPE_FRAME_BUFFER, + sizeof(DpmClocks_t), + &smu_dpm_clks.mc_address.quad_part); + + if (smu_dpm_clks.dpm_clks == NULL) { + smu_dpm_clks.dpm_clks = &dummy_clocks; + smu_dpm_clks.mc_address.quad_part = 0; + } + + ASSERT(smu_dpm_clks.dpm_clks); + + if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { + clk_mgr->base.base.funcs = &dcn3_fpga_funcs; + } else { + struct clk_log_info log_info = {0}; + + clk_mgr->base.smu_ver = dcn31_smu_get_smu_version(&clk_mgr->base); + + if (clk_mgr->base.smu_ver) + clk_mgr->base.smu_present = true; + + /* TODO: Check we get what we expect during bringup */ + clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base); + + if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { + dcn31_bw_params.wm_table = lpddr5_wm_table; + } else { + dcn31_bw_params.wm_table = ddr4_wm_table; + } + /* Saved clocks configured at boot for debug purposes */ + dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info); + + } + + clk_mgr->base.base.dprefclk_khz = 600000; + clk_mgr->base.dccg->ref_dtbclk_khz = 600000; + dce_clock_read_ss_info(&clk_mgr->base); + + clk_mgr->base.base.bw_params = &dcn31_bw_params; + + if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { + dcn31_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks); + + if (ctx->dc_bios && ctx->dc_bios->integrated_info) { + dcn31_clk_mgr_helper_populate_bw_params( + &clk_mgr->base, + ctx->dc_bios->integrated_info, + smu_dpm_clks.dpm_clks); + } + } + + if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) + dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, + smu_dpm_clks.dpm_clks); +} + +void dcn31_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) +{ + struct clk_mgr_dcn31 *clk_mgr = TO_CLK_MGR_DCN31(clk_mgr_int); + + if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) + dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, + clk_mgr->smu_wm_set.wm_set); +} diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h new file mode 100644 index 000000000000..cc21cf75eafd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h @@ -0,0 +1,103 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DCN31_CLK_MGR_H__ +#define __DCN31_CLK_MGR_H__ +#include "clk_mgr_internal.h" + +//CLK1_CLK_PLL_REQ +#ifndef CLK11_CLK1_CLK_PLL_REQ__FbMult_int__SHIFT +#define CLK11_CLK1_CLK_PLL_REQ__FbMult_int__SHIFT 0x0 +#define CLK11_CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT 0xc +#define CLK11_CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT 0x10 +#define CLK11_CLK1_CLK_PLL_REQ__FbMult_int_MASK 0x000001FFL +#define CLK11_CLK1_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000F000L +#define CLK11_CLK1_CLK_PLL_REQ__FbMult_frac_MASK 0xFFFF0000L +//CLK1_CLK0_DFS_CNTL +#define CLK11_CLK1_CLK0_DFS_CNTL__CLK0_DIVIDER__SHIFT 0x0 +#define CLK11_CLK1_CLK0_DFS_CNTL__CLK0_DIVIDER_MASK 0x0000007FL +/*DPREF clock related*/ +#define CLK0_CLK3_DFS_CNTL__CLK3_DIVIDER__SHIFT 0x0 +#define CLK0_CLK3_DFS_CNTL__CLK3_DIVIDER_MASK 0x0000007FL +#define CLK1_CLK3_DFS_CNTL__CLK3_DIVIDER__SHIFT 0x0 +#define CLK1_CLK3_DFS_CNTL__CLK3_DIVIDER_MASK 0x0000007FL +#define CLK2_CLK3_DFS_CNTL__CLK3_DIVIDER__SHIFT 0x0 +#define CLK2_CLK3_DFS_CNTL__CLK3_DIVIDER_MASK 0x0000007FL +#define CLK3_CLK3_DFS_CNTL__CLK3_DIVIDER__SHIFT 0x0 +#define CLK3_CLK3_DFS_CNTL__CLK3_DIVIDER_MASK 0x0000007FL + +//CLK3_0_CLK3_CLK_PLL_REQ +#define CLK3_0_CLK3_CLK_PLL_REQ__FbMult_int__SHIFT 0x0 +#define CLK3_0_CLK3_CLK_PLL_REQ__PllSpineDiv__SHIFT 0xc +#define CLK3_0_CLK3_CLK_PLL_REQ__FbMult_frac__SHIFT 0x10 +#define CLK3_0_CLK3_CLK_PLL_REQ__FbMult_int_MASK 0x000001FFL +#define CLK3_0_CLK3_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000F000L +#define CLK3_0_CLK3_CLK_PLL_REQ__FbMult_frac_MASK 0xFFFF0000L + +#define mmCLK0_CLK3_DFS_CNTL 0x16C60 +#define mmCLK00_CLK0_CLK3_DFS_CNTL 0x16C60 +#define mmCLK01_CLK0_CLK3_DFS_CNTL 0x16E60 +#define mmCLK02_CLK0_CLK3_DFS_CNTL 0x17060 +#define mmCLK03_CLK0_CLK3_DFS_CNTL 0x17260 + +#define mmCLK0_CLK_PLL_REQ 0x16C10 +#define mmCLK00_CLK0_CLK_PLL_REQ 0x16C10 +#define mmCLK01_CLK0_CLK_PLL_REQ 0x16E10 +#define mmCLK02_CLK0_CLK_PLL_REQ 0x17010 +#define mmCLK03_CLK0_CLK_PLL_REQ 0x17210 + +#define mmCLK1_CLK_PLL_REQ 0x1B00D +#define mmCLK10_CLK1_CLK_PLL_REQ 0x1B00D +#define mmCLK11_CLK1_CLK_PLL_REQ 0x1B20D +#define mmCLK12_CLK1_CLK_PLL_REQ 0x1B40D +#define mmCLK13_CLK1_CLK_PLL_REQ 0x1B60D + +#define mmCLK2_CLK_PLL_REQ 0x17E0D + +/*AMCLK*/ +#define mmCLK11_CLK1_CLK0_DFS_CNTL 0x1B23F +#define mmCLK11_CLK1_CLK_PLL_REQ 0x1B20D +#endif + +struct dcn31_watermarks; + +struct dcn31_smu_watermark_set { + struct dcn31_watermarks *wm_set; + union large_integer mc_address; +}; + +struct clk_mgr_dcn31 { + struct clk_mgr_internal base; + struct dcn31_smu_watermark_set smu_wm_set; +}; + +void dcn31_clk_mgr_construct(struct dc_context *ctx, + struct clk_mgr_dcn31 *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg); + +void dcn31_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int); + +#endif //__DCN31_CLK_MGR_H__ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c new file mode 100644 index 000000000000..66db5e988bc1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c @@ -0,0 +1,333 @@ +/* + * Copyright 2012-16 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include <linux/delay.h> +#include "core_types.h" +#include "clk_mgr_internal.h" +#include "reg_helper.h" +#include "dm_helpers.h" +#include "dcn31_smu.h" + +#include "yellow_carp_offset.h" +#include "mp/mp_13_0_1_offset.h" +#include "mp/mp_13_0_1_sh_mask.h" + +#define REG(reg_name) \ + (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) + +#define FN(reg_name, field) \ + FD(reg_name##__##field) + +#define VBIOSSMC_MSG_TestMessage 0x1 +#define VBIOSSMC_MSG_GetSmuVersion 0x2 +#define VBIOSSMC_MSG_PowerUpGfx 0x3 +#define VBIOSSMC_MSG_SetDispclkFreq 0x4 +#define VBIOSSMC_MSG_SetDprefclkFreq 0x5 //Not used. DPRef is constant +#define VBIOSSMC_MSG_SetDppclkFreq 0x6 +#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x7 +#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x8 +#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x9 //Keep it in case VMIN dees not support phy clk +#define VBIOSSMC_MSG_GetFclkFrequency 0xA +#define VBIOSSMC_MSG_SetDisplayCount 0xB //Not used anymore +#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC //Not used anymore +#define VBIOSSMC_MSG_UpdatePmeRestore 0xD +#define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0xE //Used for WM table txfr +#define VBIOSSMC_MSG_SetVbiosDramAddrLow 0xF +#define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10 +#define VBIOSSMC_MSG_TransferTableDram2Smu 0x11 +#define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12 +#define VBIOSSMC_MSG_GetDprefclkFreq 0x13 +#define VBIOSSMC_MSG_GetDtbclkFreq 0x14 +#define VBIOSSMC_MSG_AllowZstatesEntry 0x15 +#define VBIOSSMC_MSG_DisallowZstatesEntry 0x16 +#define VBIOSSMC_MSG_SetDtbClk 0x17 +#define VBIOSSMC_Message_Count 0x18 + +#define VBIOSSMC_Status_BUSY 0x0 +#define VBIOSSMC_Result_OK 0x1 +#define VBIOSSMC_Result_Failed 0xFF +#define VBIOSSMC_Result_UnknownCmd 0xFE +#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD +#define VBIOSSMC_Result_CmdRejectedBusy 0xFC + +/* + * Function to be used instead of REG_WAIT macro because the wait ends when + * the register is NOT EQUAL to zero, and because the translation in msg_if.h + * won't work with REG_WAIT. + */ +static uint32_t dcn31_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries) +{ + uint32_t res_val = VBIOSSMC_Status_BUSY; + + do { + res_val = REG_READ(MP1_SMN_C2PMSG_91); + if (res_val != VBIOSSMC_Status_BUSY) + break; + + if (delay_us >= 1000) + msleep(delay_us/1000); + else if (delay_us > 0) + udelay(delay_us); + } while (max_retries--); + + return res_val; +} + +int dcn31_smu_send_msg_with_param( + struct clk_mgr_internal *clk_mgr, + unsigned int msg_id, unsigned int param) +{ + uint32_t result; + + result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000); + ASSERT(result == VBIOSSMC_Result_OK); + + if (result == VBIOSSMC_Status_BUSY) { + return -1; + } + + /* First clear response register */ + REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY); + + /* Set the parameter register for the SMU message, unit is Mhz */ + REG_WRITE(MP1_SMN_C2PMSG_83, param); + + /* Trigger the message transaction by writing the message ID */ + REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); + + result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000); + + if (IS_SMU_TIMEOUT(result)) { + ASSERT(0); + dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000); + } + + return REG_READ(MP1_SMN_C2PMSG_83); +} + +int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) +{ + return dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_GetSmuVersion, + 0); +} + + +int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) +{ + int actual_dispclk_set_mhz = -1; + + if (!clk_mgr->smu_present) + return requested_dispclk_khz; + + /* Unit of SMU msg parameter is Mhz */ + actual_dispclk_set_mhz = dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDispclkFreq, + (requested_dispclk_khz + 999) / 1000); + + return actual_dispclk_set_mhz * 1000; +} + +int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) +{ + int actual_dprefclk_set_mhz = -1; + + if (!clk_mgr->smu_present) + return clk_mgr->base.dprefclk_khz; + + actual_dprefclk_set_mhz = dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDprefclkFreq, + (clk_mgr->base.dprefclk_khz + 999) / 1000); + + /* TODO: add code for programing DP DTO, currently this is down by command table */ + + return actual_dprefclk_set_mhz * 1000; +} + +int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz) +{ + int actual_dcfclk_set_mhz = -1; + + if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) + return -1; + + if (!clk_mgr->smu_present) + return requested_dcfclk_khz; + + actual_dcfclk_set_mhz = dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetHardMinDcfclkByFreq, + (requested_dcfclk_khz + 999) / 1000); + + return actual_dcfclk_set_mhz * 1000; +} + +int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz) +{ + int actual_min_ds_dcfclk_mhz = -1; + + if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) + return -1; + + if (!clk_mgr->smu_present) + return requested_min_ds_dcfclk_khz; + + actual_min_ds_dcfclk_mhz = dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetMinDeepSleepDcfclk, + (requested_min_ds_dcfclk_khz + 999) / 1000); + + return actual_min_ds_dcfclk_mhz * 1000; +} + +int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz) +{ + int actual_dppclk_set_mhz = -1; + + if (!clk_mgr->smu_present) + return requested_dpp_khz; + + actual_dppclk_set_mhz = dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDppclkFreq, + (requested_dpp_khz + 999) / 1000); + + return actual_dppclk_set_mhz * 1000; +} + +void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info) +{ + if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) + return; + + if (!clk_mgr->smu_present) + return; + + //TODO: Work with smu team to define optimization options. + dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDisplayIdleOptimizations, + idle_info); +} + +void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) +{ + union display_idle_optimization_u idle_info = { 0 }; + + if (!clk_mgr->smu_present) + return; + + if (enable) { + idle_info.idle_info.df_request_disabled = 1; + idle_info.idle_info.phy_ref_clk_off = 1; + } + + dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDisplayIdleOptimizations, + idle_info.data); +} + +void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_UpdatePmeRestore, + 0); +} + +void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param(clk_mgr, + VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high); +} + +void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param(clk_mgr, + VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low); +} + +void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param(clk_mgr, + VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS); +} + +void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param(clk_mgr, + VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS); +} + +void dcn31_smu_set_Z9_support(struct clk_mgr_internal *clk_mgr, bool support) +{ + //TODO: Work with smu team to define optimization options. + unsigned int msg_id; + + if (!clk_mgr->smu_present) + return; + + if (support) + msg_id = VBIOSSMC_MSG_AllowZstatesEntry; + else + msg_id = VBIOSSMC_MSG_DisallowZstatesEntry; + + dcn31_smu_send_msg_with_param( + clk_mgr, + msg_id, + 0); + +} + +/* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */ +void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) +{ + if (!clk_mgr->smu_present) + return; + + dcn31_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDtbClk, + enable); +} diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h new file mode 100644 index 000000000000..cd0b7e1e685f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h @@ -0,0 +1,271 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef DAL_DC_31_SMU_H_ +#define DAL_DC_31_SMU_H_ + +#ifndef PMFW_DRIVER_IF_H +#define PMFW_DRIVER_IF_H +#define PMFW_DRIVER_IF_VERSION 4 + +typedef struct { + int32_t value; + uint32_t numFractionalBits; +} FloatInIntFormat_t; + +typedef enum { + DSPCLK_DCFCLK = 0, + DSPCLK_DISPCLK, + DSPCLK_PIXCLK, + DSPCLK_PHYCLK, + DSPCLK_COUNT, +} DSPCLK_e; + +typedef struct { + uint16_t Freq; // in MHz + uint16_t Vid; // min voltage in SVI3 VID +} DisplayClockTable_t; + +typedef struct { + uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MinMclk; + uint16_t MaxMclk; + + uint8_t WmSetting; + uint8_t WmType; // Used for normal pstate change or memory retraining + uint8_t Padding[2]; +} WatermarkRowGeneric_t; + +#define NUM_WM_RANGES 4 +#define WM_PSTATE_CHG 0 +#define WM_RETRAINING 1 + +typedef enum { + WM_SOCCLK = 0, + WM_DCFCLK, + WM_COUNT, +} WM_CLOCK_e; + +typedef struct { + // Watermarks + WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES]; + + uint32_t MmHubPadding[7]; // SMU internal use +} Watermarks_t; + +typedef enum { + CUSTOM_DPM_SETTING_GFXCLK, + CUSTOM_DPM_SETTING_CCLK, + CUSTOM_DPM_SETTING_FCLK_CCX, + CUSTOM_DPM_SETTING_FCLK_GFX, + CUSTOM_DPM_SETTING_FCLK_STALLS, + CUSTOM_DPM_SETTING_LCLK, + CUSTOM_DPM_SETTING_COUNT, +} CUSTOM_DPM_SETTING_e; + +typedef struct { + uint8_t ActiveHystLimit; + uint8_t IdleHystLimit; + uint8_t FPS; + uint8_t MinActiveFreqType; + FloatInIntFormat_t MinActiveFreq; + FloatInIntFormat_t PD_Data_limit; + FloatInIntFormat_t PD_Data_time_constant; + FloatInIntFormat_t PD_Data_error_coeff; + FloatInIntFormat_t PD_Data_error_rate_coeff; +} DpmActivityMonitorCoeffExt_t; + +typedef struct { + DpmActivityMonitorCoeffExt_t DpmActivityMonitorCoeff[CUSTOM_DPM_SETTING_COUNT]; +} CustomDpmSettings_t; + +#define NUM_DCFCLK_DPM_LEVELS 8 +#define NUM_DISPCLK_DPM_LEVELS 8 +#define NUM_DPPCLK_DPM_LEVELS 8 +#define NUM_SOCCLK_DPM_LEVELS 8 +#define NUM_VCN_DPM_LEVELS 8 +#define NUM_SOC_VOLTAGE_LEVELS 8 +#define NUM_DF_PSTATE_LEVELS 4 + +typedef enum{ + WCK_RATIO_1_1 = 0, // DDR5, Wck:ck is always 1:1; + WCK_RATIO_1_2, + WCK_RATIO_1_4, + WCK_RATIO_MAX +} WCK_RATIO_e; + +typedef struct { + uint32_t FClk; + uint32_t MemClk; + uint32_t Voltage; + uint8_t WckRatio; + uint8_t Spare[3]; +} DfPstateTable_t; + +//Freq in MHz +//Voltage in milli volts with 2 fractional bits +typedef struct { + uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS]; + uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS]; + uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS]; + uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS]; + uint32_t VClocks[NUM_VCN_DPM_LEVELS]; + uint32_t DClocks[NUM_VCN_DPM_LEVELS]; + uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS]; + DfPstateTable_t DfPstateTable[NUM_DF_PSTATE_LEVELS]; + + uint8_t NumDcfClkLevelsEnabled; + uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk + uint8_t NumSocClkLevelsEnabled; + uint8_t VcnClkLevelsEnabled; //Applies to both Vclk and Dclk + uint8_t NumDfPstatesEnabled; + uint8_t spare[3]; + + uint32_t MinGfxClk; + uint32_t MaxGfxClk; +} DpmClocks_t; + + +// Throttler Status Bitmask +#define THROTTLER_STATUS_BIT_SPL 0 +#define THROTTLER_STATUS_BIT_FPPT 1 +#define THROTTLER_STATUS_BIT_SPPT 2 +#define THROTTLER_STATUS_BIT_SPPT_APU 3 +#define THROTTLER_STATUS_BIT_THM_CORE 4 +#define THROTTLER_STATUS_BIT_THM_GFX 5 +#define THROTTLER_STATUS_BIT_THM_SOC 6 +#define THROTTLER_STATUS_BIT_TDC_VDD 7 +#define THROTTLER_STATUS_BIT_TDC_SOC 8 +#define THROTTLER_STATUS_BIT_PROCHOT_CPU 9 +#define THROTTLER_STATUS_BIT_PROCHOT_GFX 10 +#define THROTTLER_STATUS_BIT_EDC_CPU 11 +#define THROTTLER_STATUS_BIT_EDC_GFX 12 + +typedef struct { + uint16_t GfxclkFrequency; //[MHz] + uint16_t SocclkFrequency; //[MHz] + uint16_t VclkFrequency; //[MHz] + uint16_t DclkFrequency; //[MHz] + uint16_t MemclkFrequency; //[MHz] + uint16_t spare; + + uint16_t GfxActivity; //[centi] + uint16_t UvdActivity; //[centi] + + uint16_t Voltage[2]; //[mV] indices: VDDCR_VDD, VDDCR_SOC + uint16_t Current[2]; //[mA] indices: VDDCR_VDD, VDDCR_SOC + uint16_t Power[2]; //[mW] indices: VDDCR_VDD, VDDCR_SOC + + //3rd party tools in Windows need this info in the case of APUs + uint16_t CoreFrequency[8]; //[MHz] + uint16_t CorePower[8]; //[mW] + uint16_t CoreTemperature[8]; //[centi-Celsius] + uint16_t L3Frequency; //[MHz] + uint16_t L3Temperature; //[centi-Celsius] + + uint16_t GfxTemperature; //[centi-Celsius] + uint16_t SocTemperature; //[centi-Celsius] + uint16_t ThrottlerStatus; + + uint16_t CurrentSocketPower; //[mW] + uint16_t StapmOriginalLimit; //[W] + uint16_t StapmCurrentLimit; //[W] + uint16_t ApuPower; //[W] + uint16_t dGpuPower; //[W] + + uint16_t VddTdcValue; //[mA] + uint16_t SocTdcValue; //[mA] + uint16_t VddEdcValue; //[mA] + uint16_t SocEdcValue; //[mA] + + uint16_t InfrastructureCpuMaxFreq; //[MHz] + uint16_t InfrastructureGfxMaxFreq; //[MHz] +} SmuMetrics_t; + + +// Workload bits +#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 0 +#define WORKLOAD_PPLIB_VIDEO_BIT 2 +#define WORKLOAD_PPLIB_VR_BIT 3 +#define WORKLOAD_PPLIB_COMPUTE_BIT 4 +#define WORKLOAD_PPLIB_CUSTOM_BIT 5 +#define WORKLOAD_PPLIB_COUNT 6 + +#define TABLE_BIOS_IF 0 // Called by BIOS +#define TABLE_WATERMARKS 1 // Called by DAL through VBIOS +#define TABLE_CUSTOM_DPM 2 // Called by Driver +#define TABLE_SPARE1 3 +#define TABLE_DPMCLOCKS 4 // Called by Driver +#define TABLE_MOMENTARY_PM 5 // Called by Tools +#define TABLE_MODERN_STDBY 6 // Called by Tools for Modern Standby Log +#define TABLE_SMU_METRICS 7 // Called by Driver +#define TABLE_COUNT 8 + +#endif + +struct dcn31_watermarks { + // Watermarks + WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES]; + + uint32_t MmHubPadding[7]; // SMU internal use +}; + +struct dcn31_smu_dpm_clks { + DpmClocks_t *dpm_clks; + union large_integer mc_address; +}; + +/* TODO: taken from vgh, may not be correct */ +struct display_idle_optimization { + unsigned int df_request_disabled : 1; + unsigned int phy_ref_clk_off : 1; + unsigned int s0i2_rdy : 1; + unsigned int reserved : 29; +}; + +union display_idle_optimization_u { + struct display_idle_optimization idle_info; + uint32_t data; +}; + +int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr); +int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz); +int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr); +int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz); +int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz); +int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz); +void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info); +void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable); +void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr); +void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high); +void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low); +void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr); +void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr); + +void dcn31_smu_set_Z9_support(struct clk_mgr_internal *clk_mgr, bool support); +void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable); + +#endif /* DAL_DC_31_SMU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index ef157b83bacd..605e297b7a59 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -303,7 +303,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state *stream, struct dc_crtc_timing_adjust *adjust) { - int i = 0; + int i; bool ret = false; stream->adjust.v_total_max = adjust->v_total_max; @@ -325,13 +325,55 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, return ret; } +/** + ***************************************************************************** + * Function: dc_stream_get_last_vrr_vtotal + * + * @brief + * Looks up the pipe context of dc_stream_state and gets the + * last VTOTAL used by DRR (Dynamic Refresh Rate) + * + * @param [in] dc: dc reference + * @param [in] stream: Initial dc stream state + * @param [in] adjust: Updated parameters for vertical_total_min and + * vertical_total_max + ***************************************************************************** + */ +bool dc_stream_get_last_used_drr_vtotal(struct dc *dc, + struct dc_stream_state *stream, + uint32_t *refresh_rate) +{ + bool status = false; + + int i = 0; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe->stream == stream && pipe->stream_res.tg) { + /* Only execute if a function pointer has been defined for + * the DC version in question + */ + if (pipe->stream_res.tg->funcs->get_last_used_drr_vtotal) { + pipe->stream_res.tg->funcs->get_last_used_drr_vtotal(pipe->stream_res.tg, refresh_rate); + + status = true; + + break; + } + } + } + + return status; +} + bool dc_stream_get_crtc_position(struct dc *dc, struct dc_stream_state **streams, int num_streams, unsigned int *v_pos, unsigned int *nom_v_pos) { /* TODO: Support multiple streams */ const struct dc_stream_state *stream = streams[0]; - int i = 0; + int i; bool ret = false; struct crtc_position position; @@ -538,7 +580,7 @@ void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream, enum dc_dynamic_expansion option) { /* OPP FMT dyn expansion updates*/ - int i = 0; + int i; struct pipe_ctx *pipe_ctx; for (i = 0; i < MAX_PIPES; i++) { @@ -596,7 +638,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream, bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream) { - int i = 0; + int i; bool ret = false; struct pipe_ctx *pipes; @@ -613,7 +655,7 @@ bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stre bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream) { - int i = 0; + int i; bool ret = false; struct pipe_ctx *pipes; @@ -639,8 +681,7 @@ void dc_stream_set_static_screen_params(struct dc *dc, int num_streams, const struct dc_static_screen_params *params) { - int i = 0; - int j = 0; + int i, j; struct pipe_ctx *pipes_affected[MAX_PIPES]; int num_pipes_affected = 0; @@ -895,7 +936,7 @@ static void disable_all_writeback_pipes_for_stream( static void apply_ctx_interdependent_lock(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream, bool lock) { - int i = 0; + int i; /* Checks if interdependent update function pointer is NULL or not, takes care of DCE110 case */ if (dc->hwss.interdependent_update_lock) @@ -1155,7 +1196,7 @@ static void enable_timing_multisync( struct dc *dc, struct dc_state *ctx) { - int i = 0, multisync_count = 0; + int i, multisync_count = 0; int pipe_count = dc->res_pool->pipe_count; struct pipe_ctx *multisync_pipes[MAX_PIPES] = { NULL }; @@ -1483,6 +1524,13 @@ static uint8_t get_stream_mask(struct dc *dc, struct dc_state *context) return stream_mask; } +#if defined(CONFIG_DRM_AMD_DC_DCN) +void dc_z10_restore(struct dc *dc) +{ + if (dc->hwss.z10_restore) + dc->hwss.z10_restore(dc); +} +#endif /* * Applies given context to HW and copy it into current context. * It's up to the user to release the src context afterwards. @@ -1496,6 +1544,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c struct dc_stream_state *dc_streams[MAX_STREAMS] = {0}; #if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_restore(dc); dc_allow_idle_optimizations(dc, false); #endif @@ -1918,8 +1967,13 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (u->plane_info->dcc.enable != u->surface->dcc.enable || u->plane_info->dcc.independent_64b_blks != u->surface->dcc.independent_64b_blks || u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) { + /* During DCC on/off, stutter period is calculated before + * DCC has fully transitioned. This results in incorrect + * stutter period calculation. Triggering a full update will + * recalculate stutter period. + */ update_flags->bits.dcc_change = 1; - elevate_update_type(&update_type, UPDATE_TYPE_MED); + elevate_update_type(&update_type, UPDATE_TYPE_FULL); } if (resource_pixel_format_to_bpp(u->plane_info->format) != @@ -2570,6 +2624,10 @@ static void commit_planes_for_stream(struct dc *dc, int i, j; struct pipe_ctx *top_pipe_to_program = NULL; +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_restore(dc); +#endif + if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) { /* Optimize seamless boot flag keeps clocks and watermarks high until * first flip. After first flip, optimization is required to lower @@ -3025,6 +3083,9 @@ void dc_set_power_state( case DC_ACPI_CM_POWER_STATE_D0: dc_resource_state_construct(dc, dc->current_state); +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_restore(dc); +#endif if (dc->ctx->dmub_srv) dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv); @@ -3257,10 +3318,13 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable) continue; if (link->psr_settings.psr_feature_enabled) { - if (enable && !link->psr_settings.psr_allow_active) - return dc_link_set_psr_allow_active(link, true, false, false); - else if (!enable && link->psr_settings.psr_allow_active) - return dc_link_set_psr_allow_active(link, false, true, false); + if (enable && !link->psr_settings.psr_allow_active) { + if (!dc_link_set_psr_allow_active(link, true, false, false)) + return false; + } else if (!enable && link->psr_settings.psr_allow_active) { + if (!dc_link_set_psr_allow_active(link, false, true, false)) + return false; + } } } @@ -3335,18 +3399,10 @@ void dc_hardware_release(struct dc *dc) #endif /** - ***************************************************************************** - * Function: dc_enable_dmub_notifications - * - * @brief - * Returns whether dmub notification can be enabled - * - * @param - * [in] dc: dc structure + * dc_enable_dmub_notifications - Returns whether dmub notification can be enabled + * @dc: dc structure * - * @return - * True to enable dmub notifications, False otherwise - ***************************************************************************** + * Returns: True to enable dmub notifications, False otherwise */ bool dc_enable_dmub_notifications(struct dc *dc) { @@ -3355,21 +3411,13 @@ bool dc_enable_dmub_notifications(struct dc *dc) } /** - ***************************************************************************** - * Function: dc_process_dmub_aux_transfer_async - * - * @brief - * Submits aux command to dmub via inbox message - * Sets port index appropriately for legacy DDC + * dc_process_dmub_aux_transfer_async - Submits aux command to dmub via inbox message + * Sets port index appropriately for legacy DDC + * @dc: dc structure + * @link_index: link index + * @payload: aux payload * - * @param - * [in] dc: dc structure - * [in] link_index: link index - * [in] payload: aux payload - * - * @return - * True if successful, False if failure - ***************************************************************************** + * Returns: True if successful, False if failure */ bool dc_process_dmub_aux_transfer_async(struct dc *dc, uint32_t link_index, @@ -3428,16 +3476,8 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc, } /** - ***************************************************************************** - * Function: dc_disable_accelerated_mode - * - * @brief - * disable accelerated mode - * - * @param - * [in] dc: dc structure - * - ***************************************************************************** + * dc_disable_accelerated_mode - disable accelerated mode + * @dc: dc structure */ void dc_disable_accelerated_mode(struct dc *dc) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 2a9080400bdd..9039fb134db5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -291,3 +291,136 @@ bool hwss_wait_for_blank_complete( return true; } + +void get_mpctree_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + const struct tg_color pipe_colors[6] = { + {MAX_TG_COLOR_VALUE, 0, 0}, /* red */ + {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE / 4, 0}, /* orange */ + {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE, 0}, /* yellow */ + {0, MAX_TG_COLOR_VALUE, 0}, /* green */ + {0, 0, MAX_TG_COLOR_VALUE}, /* blue */ + {MAX_TG_COLOR_VALUE / 2, 0, MAX_TG_COLOR_VALUE / 2}, /* purple */ + }; + + struct pipe_ctx *top_pipe = pipe_ctx; + + while (top_pipe->top_pipe) + top_pipe = top_pipe->top_pipe; + + *color = pipe_colors[top_pipe->pipe_idx]; +} + +void get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + + switch (pipe_ctx->plane_res.scl_data.format) { + case PIXEL_FORMAT_ARGB8888: + /* set border color to red */ + color->color_r_cr = color_value; + if (pipe_ctx->plane_state->layer_index > 0) { + /* set border color to pink */ + color->color_b_cb = color_value; + color->color_g_y = color_value * 0.5; + } + break; + + case PIXEL_FORMAT_ARGB2101010: + /* set border color to blue */ + color->color_b_cb = color_value; + if (pipe_ctx->plane_state->layer_index > 0) { + /* set border color to cyan */ + color->color_g_y = color_value; + } + break; + case PIXEL_FORMAT_420BPP8: + /* set border color to green */ + color->color_g_y = color_value; + break; + case PIXEL_FORMAT_420BPP10: + /* set border color to yellow */ + color->color_g_y = color_value; + color->color_r_cr = color_value; + break; + case PIXEL_FORMAT_FP16: + /* set border color to white */ + color->color_r_cr = color_value; + color->color_b_cb = color_value; + color->color_g_y = color_value; + if (pipe_ctx->plane_state->layer_index > 0) { + /* set border color to orange */ + color->color_g_y = 0.22 * color_value; + color->color_b_cb = 0; + } + break; + default: + break; + } +} + +void get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + + /* Determine the overscan color based on the top-most (desktop) plane's context */ + struct pipe_ctx *top_pipe_ctx = pipe_ctx; + + while (top_pipe_ctx->top_pipe != NULL) + top_pipe_ctx = top_pipe_ctx->top_pipe; + + switch (top_pipe_ctx->plane_res.scl_data.format) { + case PIXEL_FORMAT_ARGB2101010: + if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { + /* HDR10, ARGB2101010 - set border color to red */ + color->color_r_cr = color_value; + } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { + /* FreeSync 2 ARGB2101010 - set border color to pink */ + color->color_r_cr = color_value; + color->color_b_cb = color_value; + } + break; + case PIXEL_FORMAT_FP16: + if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { + /* HDR10, FP16 - set border color to blue */ + color->color_b_cb = color_value; + } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { + /* FreeSync 2 HDR - set border color to green */ + color->color_g_y = color_value; + } + break; + default: + /* SDR - set border color to Gray */ + color->color_r_cr = color_value/2; + color->color_b_cb = color_value/2; + color->color_g_y = color_value/2; + break; + } +} + +void get_surface_tile_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + /* Determine the overscan color based on the bottom-most plane's context */ + struct pipe_ctx *bottom_pipe_ctx = pipe_ctx; + + while (bottom_pipe_ctx->bottom_pipe != NULL) + bottom_pipe_ctx = bottom_pipe_ctx->bottom_pipe; + + switch (bottom_pipe_ctx->plane_state->tiling_info.gfx9.swizzle) { + case DC_SW_LINEAR: + /* LINEAR Surface - set border color to red */ + color->color_r_cr = color_value; + break; + default: + break; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index c07b45c021d5..6132b645bfd1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -49,6 +49,7 @@ #include "dmub/dmub_srv.h" #include "inc/hw/panel_cntl.h" #include "inc/link_enc_cfg.h" +#include "inc/link_dpcd.h" #define DC_LOGGER_INIT(logger) @@ -59,20 +60,6 @@ #define RETIMER_REDRIVER_INFO(...) \ DC_LOG_RETIMER_REDRIVER( \ __VA_ARGS__) -/******************************************************************************* - * Private structures - ******************************************************************************/ - -enum { - PEAK_FACTOR_X1000 = 1006, - /* - * Some receivers fail to train on first try and are good - * on subsequent tries. 2 retries should be plenty. If we - * don't have a successful training then we don't expect to - * ever get one. - */ - LINK_TRAINING_MAX_VERIFY_RETRY = 2 -}; /******************************************************************************* * Private functions @@ -718,11 +705,9 @@ static void read_current_link_settings_on_detect(struct dc_link *link) static bool detect_dp(struct dc_link *link, struct display_sink_capability *sink_caps, - bool *converter_disable_audio, - struct audio_support *audio_support, enum dc_detect_reason reason) { - bool boot = false; + struct audio_support *audio_support = &link->dc->res_pool->audio_support; sink_caps->signal = link_detect_sink(link, reason); sink_caps->transaction_type = @@ -745,60 +730,12 @@ static bool detect_dp(struct dc_link *link, * of this function). */ query_hdcp_capability(SIGNAL_TYPE_DISPLAY_PORT_MST, link); #endif - /* - * This call will initiate MST topology discovery. Which - * will detect MST ports and add new DRM connector DRM - * framework. Then read EDID via remote i2c over aux. In - * the end, will notify DRM detect result and save EDID - * into DRM framework. - * - * .detect is called by .fill_modes. - * .fill_modes is called by user mode ioctl - * DRM_IOCTL_MODE_GETCONNECTOR. - * - * .get_modes is called by .fill_modes. - * - * call .get_modes, AMDGPU DM implementation will create - * new dc_sink and add to dc_link. For long HPD plug - * in/out, MST has its own handle. - * - * Therefore, just after dc_create, link->sink is not - * created for MST until user mode app calls - * DRM_IOCTL_MODE_GETCONNECTOR. - * - * Need check ->sink usages in case ->sink = NULL - * TODO: s3 resume check - */ - if (reason == DETECT_REASON_BOOT) - boot = true; - - dm_helpers_dp_update_branch_info(link->ctx, link); - - if (!dm_helpers_dp_mst_start_top_mgr(link->ctx, - link, boot)) { - /* MST not supported */ - link->type = dc_connection_single; - sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT; - } } if (link->type != dc_connection_mst_branch && - is_dp_branch_device(link)) { + is_dp_branch_device(link)) /* DP SST branch */ link->type = dc_connection_sst_branch; - if (!link->dpcd_caps.sink_count.bits.SINK_COUNT) { - /* - * SST branch unplug processing for short irq - */ - link_disconnect_sink(link); - return true; - } - - if (is_dp_active_dongle(link) && - (link->dpcd_caps.dongle_type != - DISPLAY_DONGLE_DP_HDMI_CONVERTER)) - *converter_disable_audio = true; - } } else { /* DP passive dongles */ sink_caps->signal = dp_passive_dongle_detection(link->ddc, @@ -884,7 +821,7 @@ static bool dc_link_detect_helper(struct dc_link *link, { struct dc_sink_init_data sink_init_data = { 0 }; struct display_sink_capability sink_caps = { 0 }; - uint8_t i; + uint32_t i; bool converter_disable_audio = false; struct audio_support *aud_support = &link->dc->res_pool->audio_support; bool same_edid = false; @@ -893,7 +830,6 @@ static bool dc_link_detect_helper(struct dc_link *link, struct dc_sink *sink = NULL; struct dc_sink *prev_sink = NULL; struct dpcd_caps prev_dpcd_caps; - bool same_dpcd = true; enum dc_connection_type new_connection_type = dc_connection_none; enum dc_connection_type pre_connection_type = dc_connection_none; bool perform_dp_seamless_boot = false; @@ -904,9 +840,10 @@ static bool dc_link_detect_helper(struct dc_link *link, if (dc_is_virtual_signal(link->connector_signal)) return false; - if ((link->connector_signal == SIGNAL_TYPE_LVDS || - link->connector_signal == SIGNAL_TYPE_EDP) && - link->local_sink) { + if (((link->connector_signal == SIGNAL_TYPE_LVDS || + link->connector_signal == SIGNAL_TYPE_EDP) && + (!link->dc->config.allow_edp_hotplug_detection)) && + link->local_sink) { // need to re-write OUI and brightness in resume case if (link->connector_signal == SIGNAL_TYPE_EDP) { dpcd_set_source_specific_data(link); @@ -983,20 +920,59 @@ static bool dc_link_detect_helper(struct dc_link *link, return false; } - if (!detect_dp(link, &sink_caps, - &converter_disable_audio, - aud_support, reason)) { + if (!detect_dp(link, &sink_caps, reason)) { if (prev_sink) dc_sink_release(prev_sink); return false; } - // Check if dpcp block is the same - if (prev_sink) { - if (memcmp(&link->dpcd_caps, &prev_dpcd_caps, - sizeof(struct dpcd_caps))) - same_dpcd = false; + if (link->type == dc_connection_mst_branch) { + LINK_INFO("link=%d, mst branch is now Connected\n", + link->link_index); + /* Need to setup mst link_cap struct here + * otherwise dc_link_detect() will leave mst link_cap + * empty which leads to allocate_mst_payload() has "0" + * pbn_per_slot value leading to exception on dc_fixpt_div() + */ + dp_verify_mst_link_cap(link); + + /* + * This call will initiate MST topology discovery. Which + * will detect MST ports and add new DRM connector DRM + * framework. Then read EDID via remote i2c over aux. In + * the end, will notify DRM detect result and save EDID + * into DRM framework. + * + * .detect is called by .fill_modes. + * .fill_modes is called by user mode ioctl + * DRM_IOCTL_MODE_GETCONNECTOR. + * + * .get_modes is called by .fill_modes. + * + * call .get_modes, AMDGPU DM implementation will create + * new dc_sink and add to dc_link. For long HPD plug + * in/out, MST has its own handle. + * + * Therefore, just after dc_create, link->sink is not + * created for MST until user mode app calls + * DRM_IOCTL_MODE_GETCONNECTOR. + * + * Need check ->sink usages in case ->sink = NULL + * TODO: s3 resume check + */ + + dm_helpers_dp_update_branch_info(link->ctx, link); + if (dm_helpers_dp_mst_start_top_mgr(link->ctx, + link, reason == DETECT_REASON_BOOT)) { + if (prev_sink) + dc_sink_release(prev_sink); + return false; + } else { + link->type = dc_connection_sst_branch; + sink_caps.signal = SIGNAL_TYPE_DISPLAY_PORT; + } } + /* Active SST downstream branch device unplug*/ if (link->type == dc_connection_sst_branch && link->dpcd_caps.sink_count.bits.SINK_COUNT == 0) { @@ -1006,31 +982,23 @@ static bool dc_link_detect_helper(struct dc_link *link, return true; } + /* disable audio for non DP to HDMI active sst converter */ + if (link->type == dc_connection_sst_branch && + is_dp_active_dongle(link) && + (link->dpcd_caps.dongle_type != + DISPLAY_DONGLE_DP_HDMI_CONVERTER)) + converter_disable_audio = true; + // link switch from MST to non-MST stop topology manager if (pre_connection_type == dc_connection_mst_branch && - link->type != dc_connection_mst_branch) { + link->type != dc_connection_mst_branch) dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); - } - - if (link->type == dc_connection_mst_branch) { - LINK_INFO("link=%d, mst branch is now Connected\n", - link->link_index); - /* Need to setup mst link_cap struct here - * otherwise dc_link_detect() will leave mst link_cap - * empty which leads to allocate_mst_payload() has "0" - * pbn_per_slot value leading to exception on dc_fixpt_div() - */ - dp_verify_mst_link_cap(link); - if (prev_sink) - dc_sink_release(prev_sink); - return false; - } // For seamless boot, to skip verify link cap, we read UEFI settings and set them as verified. if (reason == DETECT_REASON_BOOT && - !dc_ctx->dc->config.power_down_display_on_boot && - link->link_status.link_active) + !dc_ctx->dc->config.power_down_display_on_boot && + link->link_status.link_active) perform_dp_seamless_boot = true; if (perform_dp_seamless_boot) { @@ -1099,24 +1067,6 @@ static bool dc_link_detect_helper(struct dc_link *link, dc_is_dvi_signal(link->connector_signal)) { if (prev_sink) dc_sink_release(prev_sink); - link_disconnect_sink(link); - - return false; - } - /* - * Abort detection for DP connectors if we have - * no EDID and connector is active converter - * as there are no display downstream - * - */ - if (dc_is_dp_sst_signal(link->connector_signal) && - (link->dpcd_caps.dongle_type == - DISPLAY_DONGLE_DP_VGA_CONVERTER || - link->dpcd_caps.dongle_type == - DISPLAY_DONGLE_DP_DVI_CONVERTER)) { - if (prev_sink) - dc_sink_release(prev_sink); - link_disconnect_sink(link); return false; } @@ -1231,11 +1181,11 @@ static bool dc_link_detect_helper(struct dc_link *link, link->dongle_max_pix_clk = 0; } - LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p dpcd same=%d edid same=%d\n", + LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n", link->link_index, sink, (sink_caps.signal == SIGNAL_TYPE_NONE ? "Disconnected" : "Connected"), - prev_sink, same_dpcd, same_edid); + prev_sink, same_edid); if (prev_sink) dc_sink_release(prev_sink); @@ -1519,7 +1469,8 @@ static bool dc_link_construct(struct dc_link *link, link->connector_signal = SIGNAL_TYPE_EDP; if (link->hpd_gpio) { - link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; + if (!link->dc->config.allow_edp_hotplug_detection) + link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; link->irq_source_hpd_rx = dal_irq_get_rx_source(link->hpd_gpio); } @@ -2701,16 +2652,24 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, bool allow_active, struct dc *dc = link->ctx->dc; struct dmcu *dmcu = dc->res_pool->dmcu; struct dmub_psr *psr = dc->res_pool->psr; + unsigned int panel_inst; if (psr == NULL && force_static) return false; + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + link->psr_settings.psr_allow_active = allow_active; +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (!allow_active) + dc_z10_restore(dc); +#endif if (psr != NULL && link->psr_settings.psr_feature_enabled) { if (force_static && psr->funcs->psr_force_static) - psr->funcs->psr_force_static(psr); - psr->funcs->psr_enable(psr, allow_active, wait); + psr->funcs->psr_force_static(psr, panel_inst); + psr->funcs->psr_enable(psr, allow_active, wait, panel_inst); } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && link->psr_settings.psr_feature_enabled) dmcu->funcs->set_psr_enable(dmcu, allow_active, wait); else @@ -2724,9 +2683,13 @@ bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state) struct dc *dc = link->ctx->dc; struct dmcu *dmcu = dc->res_pool->dmcu; struct dmub_psr *psr = dc->res_pool->psr; + unsigned int panel_inst; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; if (psr != NULL && link->psr_settings.psr_feature_enabled) - psr->funcs->psr_get_state(psr, state); + psr->funcs->psr_get_state(psr, state, panel_inst); else if (dmcu != NULL && link->psr_settings.psr_feature_enabled) dmcu->funcs->get_psr_state(dmcu, state); @@ -2776,6 +2739,7 @@ bool dc_link_setup_psr(struct dc_link *link, struct dmcu *dmcu; struct dmub_psr *psr; int i; + unsigned int panel_inst; /* updateSinkPsrDpcdConfig*/ union dpcd_psr_configuration psr_configuration; @@ -2791,6 +2755,9 @@ bool dc_link_setup_psr(struct dc_link *link, if (!dmcu && !psr) return false; + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + memset(&psr_configuration, 0, sizeof(psr_configuration)); @@ -2875,8 +2842,16 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->psr_level.u32all = 0; /*skip power down the single pipe since it blocks the cstate*/ +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (link->ctx->asic_id.chip_family >= FAMILY_RV) { + psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true; + if (link->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && !dc->debug.disable_z10) + psr_context->psr_level.bits.SKIP_CRTC_DISABLE = false; + } +#else if (link->ctx->asic_id.chip_family >= FAMILY_RV) psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true; +#endif /* SMU will perform additional powerdown sequence. * For unsupported ASICs, set psr_level flag to skip PSR @@ -2897,7 +2872,8 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->frame_delay = 0; if (psr) - link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr, link, psr_context); + link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr, + link, psr_context, panel_inst); else link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context); @@ -2915,10 +2891,14 @@ void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency) { struct dc *dc = link->ctx->dc; struct dmub_psr *psr = dc->res_pool->psr; + unsigned int panel_inst; - // PSR residency measurements only supported on DMCUB + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return; + + /* PSR residency measurements only supported on DMCUB */ if (psr != NULL && link->psr_settings.psr_feature_enabled) - psr->funcs->psr_get_residency(psr, residency); + psr->funcs->psr_get_residency(psr, residency, panel_inst); else *residency = 0; } @@ -3208,8 +3188,14 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) dp_get_panel_mode(pipe_ctx->stream->link); config.otg_inst = (uint8_t) pipe_ctx->stream_res.tg->inst; + /*stream_enc_inst*/ config.dig_fe = (uint8_t) pipe_ctx->stream_res.stream_enc->stream_enc_inst; config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst; +#if defined(CONFIG_DRM_AMD_DC_DCN) + config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; + config.link_enc_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A; + config.phy_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A; +#endif config.dpms_off = dpms_off; config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context; config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 9e08410bfdfd..b8832bdde2bc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -25,7 +25,7 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; link->ctx->logger #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ -#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 +#include "link_dpcd.h" /* maximum pre emphasis level allowed for each voltage swing level*/ static const enum dc_pre_emphasis @@ -39,14 +39,6 @@ enum { POST_LT_ADJ_REQ_TIMEOUT = 200 }; -enum { - LINK_TRAINING_MAX_RETRY_COUNT = 5, - /* to avoid infinite loop where-in the receiver - * switches between different VS - */ - LINK_TRAINING_MAX_CR_RETRY = 100 -}; - static bool decide_fallback_link_setting( struct dc_link_settings initial_link_settings, struct dc_link_settings *current_link_setting, @@ -97,7 +89,7 @@ static uint32_t get_eq_training_aux_rd_interval( return wait_in_micro_secs; } -static void wait_for_training_aux_rd_interval( +void dp_wait_for_training_aux_rd_interval( struct dc_link *link, uint32_t wait_in_micro_secs) { @@ -108,7 +100,7 @@ static void wait_for_training_aux_rd_interval( wait_in_micro_secs); } -static enum dpcd_training_patterns +enum dpcd_training_patterns dc_dp_training_pattern_to_dpcd_training_pattern( struct dc_link *link, enum dc_dp_training_pattern pattern) @@ -206,11 +198,12 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li return DP_TRAINING_PATTERN_SEQUENCE_2; } -static void dpcd_set_link_settings( +enum dc_status dpcd_set_link_settings( struct dc_link *link, const struct link_training_settings *lt_settings) { uint8_t rate; + enum dc_status status; union down_spread_ctrl downspread = { {0} }; union lane_count_set lane_count_set = { {0} }; @@ -225,15 +218,16 @@ static void dpcd_set_link_settings( lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; - if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + if (link->ep_type == DISPLAY_ENDPOINT_PHY && + lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; } - core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); - core_link_write_dpcd(link, DP_LANE_COUNT_SET, + status = core_link_write_dpcd(link, DP_LANE_COUNT_SET, &lane_count_set.raw, 1); if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && @@ -249,12 +243,12 @@ static void dpcd_set_link_settings( core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, supported_link_rates, sizeof(supported_link_rates)); } - core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); - core_link_write_dpcd(link, DP_LINK_RATE_SET, + status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + status = core_link_write_dpcd(link, DP_LINK_RATE_SET, <_settings->link_settings.link_rate_set, 1); } else { rate = (uint8_t) (lt_settings->link_settings.link_rate); - core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); } if (rate) { @@ -278,9 +272,11 @@ static void dpcd_set_link_settings( DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); } + + return status; } -static uint8_t dc_dp_initialize_scrambling_data_symbols( +uint8_t dc_dp_initialize_scrambling_data_symbols( struct dc_link *link, enum dc_dp_training_pattern pattern) { @@ -429,7 +425,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( link->cur_lane_setting = lt_settings->lane_settings[0]; } -static bool is_cr_done(enum dc_lane_count ln_count, +bool dp_is_cr_done(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { uint32_t lane; @@ -441,7 +437,7 @@ static bool is_cr_done(enum dc_lane_count ln_count, return true; } -static bool is_ch_eq_done(enum dc_lane_count ln_count, +bool dp_is_ch_eq_done(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { bool done = true; @@ -452,7 +448,7 @@ static bool is_ch_eq_done(enum dc_lane_count ln_count, return done; } -static bool is_symbol_locked(enum dc_lane_count ln_count, +bool dp_is_symbol_locked(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { bool locked = true; @@ -463,12 +459,12 @@ static bool is_symbol_locked(enum dc_lane_count ln_count, return locked; } -static inline bool is_interlane_aligned(union lane_align_status_updated align_status) +bool dp_is_interlane_aligned(union lane_align_status_updated align_status) { return align_status.bits.INTERLANE_ALIGN_DONE == 1; } -static void update_drive_settings( +void dp_update_drive_settings( struct link_training_settings *dest, struct link_training_settings src) { @@ -612,7 +608,7 @@ static void find_max_drive_settings( } -static void get_lane_status_and_drive_settings( +enum dc_status dp_get_lane_status_and_drive_settings( struct dc_link *link, const struct link_training_settings *link_training_setting, union lane_status *ln_status, @@ -627,6 +623,7 @@ static void get_lane_status_and_drive_settings( union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; struct link_training_settings request_settings = { {0} }; uint32_t lane; + enum dc_status status; memset(req_settings, '\0', sizeof(struct link_training_settings)); @@ -637,7 +634,7 @@ static void get_lane_status_and_drive_settings( lane_adjust_offset = 3; } - core_link_read_dpcd( + status = core_link_read_dpcd( link, lane01_status_address, (uint8_t *)(dpcd_buf), @@ -725,9 +722,10 @@ static void get_lane_status_and_drive_settings( * read DpcdAddress_AdjustRequestPostCursor2 = 0x020C */ + return status; } -static void dpcd_set_lane_settings( +enum dc_status dpcd_set_lane_settings( struct dc_link *link, const struct link_training_settings *link_training_setting, uint32_t offset) @@ -735,6 +733,7 @@ static void dpcd_set_lane_settings( union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}}; uint32_t lane; unsigned int lane0_set_address; + enum dc_status status; lane0_set_address = DP_TRAINING_LANE0_SET; @@ -762,7 +761,7 @@ static void dpcd_set_lane_settings( PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); } - core_link_write_dpcd(link, + status = core_link_write_dpcd(link, lane0_set_address, (uint8_t *)(dpcd_lane), link_training_setting->link_settings.lane_count); @@ -808,9 +807,10 @@ static void dpcd_set_lane_settings( } link->cur_lane_setting = link_training_setting->lane_settings[0]; + return status; } -static bool is_max_vs_reached( +bool dp_is_max_vs_reached( const struct link_training_settings *lt_settings) { uint32_t lane; @@ -852,24 +852,24 @@ static bool perform_post_lt_adj_req_sequence( union lane_align_status_updated dpcd_lane_status_updated; - get_lane_status_and_drive_settings( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - &req_settings, - DPRX); + dp_get_lane_status_and_drive_settings( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + &req_settings, + DPRX); if (dpcd_lane_status_updated.bits. POST_LT_ADJ_REQ_IN_PROGRESS == 0) return true; - if (!is_cr_done(lane_count, dpcd_lane_status)) + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) return false; - if (!is_ch_eq_done(lane_count, dpcd_lane_status) || - !is_symbol_locked(lane_count, dpcd_lane_status) || - !is_interlane_aligned(dpcd_lane_status_updated)) + if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) || + !dp_is_symbol_locked(lane_count, dpcd_lane_status) || + !dp_is_interlane_aligned(dpcd_lane_status_updated)) return false; for (lane = 0; lane < (uint32_t)(lane_count); lane++) { @@ -887,7 +887,7 @@ static bool perform_post_lt_adj_req_sequence( } if (req_drv_setting_changed) { - update_drive_settings( + dp_update_drive_settings( lt_settings, req_settings); dc_link_dp_set_drive_settings(link, @@ -915,7 +915,7 @@ static bool perform_post_lt_adj_req_sequence( } /* Only used for channel equalization */ -static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) +uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) { unsigned int aux_rd_interval_us = 400; @@ -939,7 +939,7 @@ static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_inte return aux_rd_interval_us; } -static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, +enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { enum link_training_result result = LINK_TRAINING_SUCCESS; @@ -1000,17 +1000,17 @@ static enum link_training_result perform_channel_equalization_sequence( if (is_repeater(link, offset)) wait_time_microsec = - translate_training_aux_read_interval( + dp_translate_training_aux_read_interval( link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); - wait_for_training_aux_rd_interval( + dp_wait_for_training_aux_rd_interval( link, wait_time_microsec); /* 4. Read lane status and requested * drive settings as set by the sink*/ - get_lane_status_and_drive_settings( + dp_get_lane_status_and_drive_settings( link, lt_settings, dpcd_lane_status, @@ -1019,23 +1019,22 @@ static enum link_training_result perform_channel_equalization_sequence( offset); /* 5. check CR done*/ - if (!is_cr_done(lane_count, dpcd_lane_status)) + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) return LINK_TRAINING_EQ_FAIL_CR; /* 6. check CHEQ done*/ - if (is_ch_eq_done(lane_count, dpcd_lane_status) && - is_symbol_locked(lane_count, dpcd_lane_status) && - is_interlane_aligned(dpcd_lane_status_updated)) + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) return LINK_TRAINING_SUCCESS; /* 7. update VS/PE/PC2 in lt_settings*/ - update_drive_settings(lt_settings, req_settings); + dp_update_drive_settings(lt_settings, req_settings); } return LINK_TRAINING_EQ_FAIL_EQ; } -#define TRAINING_AUX_RD_INTERVAL 100 //us static void start_clock_recovery_pattern_early(struct dc_link *link, struct link_training_settings *lt_settings, @@ -1106,14 +1105,14 @@ static enum link_training_result perform_clock_recovery_sequence( if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) wait_time_microsec = TRAINING_AUX_RD_INTERVAL; - wait_for_training_aux_rd_interval( + dp_wait_for_training_aux_rd_interval( link, wait_time_microsec); /* 4. Read lane status and requested drive * settings as set by the sink */ - get_lane_status_and_drive_settings( + dp_get_lane_status_and_drive_settings( link, lt_settings, dpcd_lane_status, @@ -1122,11 +1121,11 @@ static enum link_training_result perform_clock_recovery_sequence( offset); /* 5. check CR done*/ - if (is_cr_done(lane_count, dpcd_lane_status)) + if (dp_is_cr_done(lane_count, dpcd_lane_status)) return LINK_TRAINING_SUCCESS; /* 6. max VS reached*/ - if (is_max_vs_reached(lt_settings)) + if (dp_is_max_vs_reached(lt_settings)) break; /* 7. same lane settings*/ @@ -1141,7 +1140,7 @@ static enum link_training_result perform_clock_recovery_sequence( retries_cr = 0; /* 8. update VS/PE/PC2 in lt_settings*/ - update_drive_settings(lt_settings, req_settings); + dp_update_drive_settings(lt_settings, req_settings); retry_count++; } @@ -1154,7 +1153,7 @@ static enum link_training_result perform_clock_recovery_sequence( } - return get_cr_failure(lane_count, dpcd_lane_status); + return dp_get_cr_failure(lane_count, dpcd_lane_status); } static inline enum link_training_result dp_transition_to_video_idle( @@ -1173,8 +1172,16 @@ static inline enum link_training_result dp_transition_to_video_idle( * TPS4 must be used instead of POST_LT_ADJ_REQ. */ if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || - lt_settings->pattern_for_eq == DP_TRAINING_PATTERN_SEQUENCE_4) + lt_settings->pattern_for_eq == DP_TRAINING_PATTERN_SEQUENCE_4) { + /* delay 5ms after Main Link output idle pattern and then check + * DPCD 0202h. + */ + if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { + msleep(5); + status = dp_check_link_loss_status(link, lt_settings); + } return status; + } if (status == LINK_TRAINING_SUCCESS && perform_post_lt_adj_req_sequence(link, lt_settings) == false) @@ -1327,9 +1334,14 @@ static inline void decide_8b_10b_training_settings( lt_settings->enhanced_framing = *overrides->enhanced_framing; else lt_settings->enhanced_framing = 1; + + if (link->preferred_training_settings.fec_enable != NULL) + lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; + else + lt_settings->should_set_fec_ready = true; } -static void decide_training_settings( +void dp_decide_training_settings( struct dc_link *link, const struct dc_link_settings *link_settings, const struct dc_link_training_overrides *overrides, @@ -1365,18 +1377,18 @@ uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count) return 0; // invalid value } -static void configure_lttpr_mode_transparent(struct dc_link *link) +enum dc_status configure_lttpr_mode_transparent(struct dc_link *link) { uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); - core_link_write_dpcd(link, + return core_link_write_dpcd(link, DP_PHY_REPEATER_MODE, (uint8_t *)&repeater_mode, sizeof(repeater_mode)); } -static void configure_lttpr_mode_non_transparent( +enum dc_status configure_lttpr_mode_non_transparent( struct dc_link *link, const struct link_training_settings *lt_settings) { @@ -1431,6 +1443,8 @@ static void configure_lttpr_mode_non_transparent( } } } + + return result; } static void repeater_training_done(struct dc_link *link, uint32_t offset) @@ -1564,7 +1578,7 @@ bool dc_link_dp_perform_link_training_skip_aux( { struct link_training_settings lt_settings; - decide_training_settings( + dp_decide_training_settings( link, link_setting, &link->preferred_training_settings, @@ -1579,7 +1593,7 @@ bool dc_link_dp_perform_link_training_skip_aux( dp_set_hw_lane_settings(link, <_settings, DPRX); /* wait receiver to lock-on*/ - wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); + dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); /* 2. Perform_channel_equalization_sequence. */ @@ -1590,7 +1604,7 @@ bool dc_link_dp_perform_link_training_skip_aux( dp_set_hw_lane_settings(link, <_settings, DPRX); /* wait receiver to lock-on. */ - wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); + dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); /* 3. Perform_link_training_int. */ @@ -1602,42 +1616,61 @@ bool dc_link_dp_perform_link_training_skip_aux( return true; } -enum link_training_result dc_link_dp_perform_link_training( - struct dc_link *link, - const struct dc_link_settings *link_setting, - bool skip_video_pattern) +enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings) { - enum link_training_result status = LINK_TRAINING_SUCCESS; - struct link_training_settings lt_settings; + enum dc_status status = DC_OK; - bool fec_enable; - uint8_t repeater_cnt; - uint8_t repeater_id; + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) + status = configure_lttpr_mode_non_transparent(link, lt_settings); + else + status = configure_lttpr_mode_transparent(link); - decide_training_settings( + return status; +} + +static void dpcd_exit_training_mode(struct dc_link *link) +{ + + /* clear training pattern set */ + dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); +} + +enum dc_status dpcd_configure_channel_coding(struct dc_link *link, + struct link_training_settings *lt_settings) +{ + enum dp_link_encoding encoding = + dp_get_link_encoding_format( + <_settings->link_settings); + enum dc_status status; + + status = core_link_write_dpcd( link, - link_setting, - &link->preferred_training_settings, - <_settings); + DP_MAIN_LINK_CHANNEL_CODING_SET, + (uint8_t *) &encoding, + 1); + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n", + __func__, + DP_MAIN_LINK_CHANNEL_CODING_SET, + encoding); + + return status; +} - /* Configure lttpr mode */ - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - configure_lttpr_mode_non_transparent(link, <_settings); - else if (link->lttpr_mode == LTTPR_MODE_TRANSPARENT) - configure_lttpr_mode_transparent(link); +static enum link_training_result dp_perform_8b_10b_link_training( + struct dc_link *link, + struct link_training_settings *lt_settings) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + + uint8_t repeater_cnt; + uint8_t repeater_id; + uint8_t lane = 0; if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, <_settings, DPRX); + start_clock_recovery_pattern_early(link, lt_settings, DPRX); /* 1. set link rate, lane count and spread. */ - dpcd_set_link_settings(link, <_settings); - - if (link->preferred_training_settings.fec_enable != NULL) - fec_enable = *link->preferred_training_settings.fec_enable; - else - fec_enable = true; - - dp_set_fec_ready(link, fec_enable); + dpcd_set_link_settings(link, lt_settings); if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { @@ -1648,13 +1681,13 @@ enum link_training_result dc_link_dp_perform_link_training( for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); repeater_id--) { - status = perform_clock_recovery_sequence(link, <_settings, repeater_id); + status = perform_clock_recovery_sequence(link, lt_settings, repeater_id); if (status != LINK_TRAINING_SUCCESS) break; status = perform_channel_equalization_sequence(link, - <_settings, + lt_settings, repeater_id); if (status != LINK_TRAINING_SUCCESS) @@ -1662,76 +1695,69 @@ enum link_training_result dc_link_dp_perform_link_training( repeater_training_done(link, repeater_id); } + + for (lane = 0; lane < (uint8_t)lt_settings->link_settings.lane_count; lane++) + lt_settings->lane_settings[lane].VOLTAGE_SWING = VOLTAGE_SWING_LEVEL0; } if (status == LINK_TRAINING_SUCCESS) { - status = perform_clock_recovery_sequence(link, <_settings, DPRX); + status = perform_clock_recovery_sequence(link, lt_settings, DPRX); if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, - <_settings, + lt_settings, DPRX); } } - /* 3. set training not in progress*/ - dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); - if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { - status = dp_transition_to_video_idle(link, - <_settings, - status); - } - - /* delay 5ms after Main Link output idle pattern and then check - * DPCD 0202h. - */ - if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { - msleep(5); - status = dp_check_link_loss_status(link, <_settings); - } - - /* 6. print status message*/ - print_status_message(link, <_settings, status); - - if (status != LINK_TRAINING_SUCCESS) - link->ctx->dc->debug_data.ltFailCount++; - return status; } -static enum dp_panel_mode try_enable_assr(struct dc_stream_state *stream) +enum link_training_result dc_link_dp_perform_link_training( + struct dc_link *link, + const struct dc_link_settings *link_settings, + bool skip_video_pattern) { - struct dc_link *link = stream->link; - enum dp_panel_mode panel_mode = dp_get_panel_mode(link); -#ifdef CONFIG_DRM_AMD_DC_HDCP - struct cp_psp *cp_psp = &stream->ctx->cp_psp; -#endif + enum link_training_result status = LINK_TRAINING_SUCCESS; + struct link_training_settings lt_settings; + enum dp_link_encoding encoding = + dp_get_link_encoding_format(link_settings); - /* ASSR must be supported on the panel */ - if (panel_mode == DP_PANEL_MODE_DEFAULT) - return panel_mode; + /* decide training settings */ + dp_decide_training_settings( + link, + link_settings, + &link->preferred_training_settings, + <_settings); - /* eDP or internal DP only */ - if (link->connector_signal != SIGNAL_TYPE_EDP && - !(link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && - link->is_internal_display)) - return DP_PANEL_MODE_DEFAULT; + /* reset previous training states */ + dpcd_exit_training_mode(link); -#ifdef CONFIG_DRM_AMD_DC_HDCP - if (cp_psp && cp_psp->funcs.enable_assr) { - if (!cp_psp->funcs.enable_assr(cp_psp->handle, link)) { - /* since eDP implies ASSR on, change panel - * mode to disable ASSR - */ - panel_mode = DP_PANEL_MODE_DEFAULT; - } - } else - panel_mode = DP_PANEL_MODE_DEFAULT; + /* configure link prior to entering training mode */ + dpcd_configure_lttpr_mode(link, <_settings); + dp_set_fec_ready(link, lt_settings.should_set_fec_ready); + dpcd_configure_channel_coding(link, <_settings); -#else - /* turn off ASSR if the implementation is not compiled in */ - panel_mode = DP_PANEL_MODE_DEFAULT; -#endif - return panel_mode; + /* enter training mode: + * Per DP specs starting from here, DPTX device shall not issue + * Non-LT AUX transactions inside training mode. + */ + if (encoding == DP_8b_10b_ENCODING) + status = dp_perform_8b_10b_link_training(link, <_settings); + else + ASSERT(0); + + /* exit training mode and switch to video idle */ + dpcd_exit_training_mode(link); + if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) + status = dp_transition_to_video_idle(link, + <_settings, + status); + + /* dump debug data */ + print_status_message(link, <_settings, status); + if (status != LINK_TRAINING_SUCCESS) + link->ctx->dc->debug_data.ltFailCount++; + return status; } bool perform_link_training_with_retries( @@ -1742,14 +1768,14 @@ bool perform_link_training_with_retries( enum signal_type signal, bool do_fallback) { - uint8_t j; + int j; uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; - enum dp_panel_mode panel_mode; + enum dp_panel_mode panel_mode = dp_get_panel_mode(link); struct link_encoder *link_enc; enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; - struct dc_link_settings currnet_setting = *link_setting; + struct dc_link_settings current_setting = *link_setting; /* Dynamically assigned link encoders associated with stream rather than * link. @@ -1775,7 +1801,7 @@ bool perform_link_training_with_retries( link, signal, pipe_ctx->clock_source->id, - &currnet_setting); + ¤t_setting); if (stream->sink_patches.dppowerup_delay > 0) { int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; @@ -1783,19 +1809,31 @@ bool perform_link_training_with_retries( msleep(delay_dp_power_up_in_ms); } - panel_mode = try_enable_assr(stream); +#ifdef CONFIG_DRM_AMD_DC_HDCP + if (panel_mode == DP_PANEL_MODE_EDP) { + struct cp_psp *cp_psp = &stream->ctx->cp_psp; + + if (cp_psp && cp_psp->funcs.enable_assr) { + if (!cp_psp->funcs.enable_assr(cp_psp->handle, link)) { + /* since eDP implies ASSR on, change panel + * mode to disable ASSR + */ + panel_mode = DP_PANEL_MODE_DEFAULT; + } + } else + panel_mode = DP_PANEL_MODE_DEFAULT; + } +#endif + dp_set_panel_mode(link, panel_mode); - DC_LOG_DETECTION_DP_CAPS("Link: %d ASSR enabled: %d\n", - link->link_index, - panel_mode != DP_PANEL_MODE_DEFAULT); if (link->aux_access_disabled) { - dc_link_dp_perform_link_training_skip_aux(link, &currnet_setting); + dc_link_dp_perform_link_training_skip_aux(link, ¤t_setting); return true; } else { status = dc_link_dp_perform_link_training( link, - &currnet_setting, + ¤t_setting, skip_video_pattern); if (status == LINK_TRAINING_SUCCESS) return true; @@ -1815,12 +1853,12 @@ bool perform_link_training_with_retries( if (status == LINK_TRAINING_ABORT) break; else if (do_fallback) { - decide_fallback_link_setting(*link_setting, &currnet_setting, status); + decide_fallback_link_setting(*link_setting, ¤t_setting, status); /* Fail link training if reduced link bandwidth no longer meets * stream requirements. */ if (dc_bandwidth_in_kbps_from_timing(&stream->timing) < - dc_link_bandwidth_kbps(link, &currnet_setting)) + dc_link_bandwidth_kbps(link, ¤t_setting)) break; } @@ -1860,6 +1898,8 @@ static void set_dp_mst_mode(struct dc_link *link, bool mst_enable) link->type = dc_connection_single; link->local_sink = link->remote_sinks[0]; link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; + dc_sink_retain(link->local_sink); + dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); } else if (mst_enable == true && link->type == dc_connection_single && link->remote_sinks[0] != NULL) { @@ -1899,7 +1939,7 @@ enum link_training_result dc_link_dp_sync_lt_attempt( enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; bool fec_enable = false; - decide_training_settings( + dp_decide_training_settings( link, link_settings, lt_overrides, @@ -2070,7 +2110,7 @@ enum dc_status read_hpd_rx_irq_data( return retval; } -static bool hpd_rx_irq_check_link_loss_status( +bool hpd_rx_irq_check_link_loss_status( struct dc_link *link, union hpd_irq_data *hpd_irq_dpcd_data) { @@ -2267,7 +2307,7 @@ bool dp_verify_link_cap_with_retries( struct dc_link_settings *known_limit_link_setting, int attempts) { - uint8_t i = 0; + int i = 0; bool success = false; for (i = 0; i < attempts; i++) { @@ -3560,79 +3600,16 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } -static bool retrieve_link_cap(struct dc_link *link) +bool dp_retrieve_lttpr_cap(struct dc_link *link) { - /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, - * which means size 16 will be good for both of those DPCD register block reads - */ - uint8_t dpcd_data[16]; uint8_t lttpr_dpcd_data[6]; - - /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. - */ - uint8_t dpcd_dprx_data = '\0'; - uint8_t dpcd_power_state = '\0'; - - struct dp_device_vendor_id sink_id; - union down_stream_port_count down_strm_port_count; - union edp_configuration_cap edp_config_cap; - union dp_downstream_port_present ds_port = { 0 }; - enum dc_status status = DC_ERROR_UNEXPECTED; - uint32_t read_dpcd_retry_cnt = 3; - int i; - struct dp_sink_hw_fw_revision dp_hw_fw_revision; - bool is_lttpr_present = false; - const uint32_t post_oui_delay = 30; // 30ms bool vbios_lttpr_enable = false; bool vbios_lttpr_interop = false; struct dc_bios *bios = link->dc->ctx->dc_bios; + enum dc_status status = DC_ERROR_UNEXPECTED; + bool is_lttpr_present = false; - memset(dpcd_data, '\0', sizeof(dpcd_data)); memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data)); - memset(&down_strm_port_count, - '\0', sizeof(union down_stream_port_count)); - memset(&edp_config_cap, '\0', - sizeof(union edp_configuration_cap)); - - /* if extended timeout is supported in hardware, - * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer - * CTS 4.2.1.1 regression introduced by CTS specs requirement update. - */ - dc_link_aux_try_to_configure_timeout(link->ddc, - LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); - - status = core_link_read_dpcd(link, DP_SET_POWER, - &dpcd_power_state, sizeof(dpcd_power_state)); - - /* Delay 1 ms if AUX CH is in power down state. Based on spec - * section 2.3.1.2, if AUX CH may be powered down due to - * write to DPCD 600h = 2. Sink AUX CH is monitoring differential - * signal and may need up to 1 ms before being able to reply. - */ - if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) - udelay(1000); - - dpcd_set_source_specific_data(link); - /* Sink may need to configure internals based on vendor, so allow some - * time before proceeding with possibly vendor specific transactions - */ - msleep(post_oui_delay); - - for (i = 0; i < read_dpcd_retry_cnt; i++) { - status = core_link_read_dpcd( - link, - DP_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); - if (status == DC_OK) - break; - } - - if (status != DC_OK) { - dm_error("%s: Read dpcd data failed.\n", __func__); - return false; - } - /* Query BIOS to determine if LTTPR functionality is forced on by system */ if (bios->funcs->get_lttpr_caps) { enum bp_result bp_query_result; @@ -3678,6 +3655,10 @@ static bool retrieve_link_cap(struct dc_link *link) DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, lttpr_dpcd_data, sizeof(lttpr_dpcd_data)); + if (status != DC_OK) { + dm_error("%s: Read LTTPR caps data failed.\n", __func__); + return false; + } link->dpcd_caps.lttpr_caps.revision.raw = lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - @@ -3704,21 +3685,91 @@ static bool retrieve_link_cap(struct dc_link *link) DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ - is_lttpr_present = (link->dpcd_caps.lttpr_caps.phy_repeater_cnt > 0 && - link->dpcd_caps.lttpr_caps.phy_repeater_cnt < 0xff && + is_lttpr_present = (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 && link->dpcd_caps.lttpr_caps.max_lane_count > 0 && link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); - if (is_lttpr_present) + if (is_lttpr_present) { CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); - else + configure_lttpr_mode_transparent(link); + } else link->lttpr_mode = LTTPR_MODE_NON_LTTPR; } + return is_lttpr_present; +} + +static bool retrieve_link_cap(struct dc_link *link) +{ + /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, + * which means size 16 will be good for both of those DPCD register block reads + */ + uint8_t dpcd_data[16]; + /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. + */ + uint8_t dpcd_dprx_data = '\0'; + uint8_t dpcd_power_state = '\0'; + + struct dp_device_vendor_id sink_id; + union down_stream_port_count down_strm_port_count; + union edp_configuration_cap edp_config_cap; + union dp_downstream_port_present ds_port = { 0 }; + enum dc_status status = DC_ERROR_UNEXPECTED; + uint32_t read_dpcd_retry_cnt = 3; + int i; + struct dp_sink_hw_fw_revision dp_hw_fw_revision; + const uint32_t post_oui_delay = 30; // 30ms + bool is_lttpr_present = false; + + memset(dpcd_data, '\0', sizeof(dpcd_data)); + memset(&down_strm_port_count, + '\0', sizeof(union down_stream_port_count)); + memset(&edp_config_cap, '\0', + sizeof(union edp_configuration_cap)); + + /* if extended timeout is supported in hardware, + * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer + * CTS 4.2.1.1 regression introduced by CTS specs requirement update. + */ + dc_link_aux_try_to_configure_timeout(link->ddc, + LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); + + is_lttpr_present = dp_retrieve_lttpr_cap(link); + + status = core_link_read_dpcd(link, DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + + /* Delay 1 ms if AUX CH is in power down state. Based on spec + * section 2.3.1.2, if AUX CH may be powered down due to + * write to DPCD 600h = 2. Sink AUX CH is monitoring differential + * signal and may need up to 1 ms before being able to reply. + */ + if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) + udelay(1000); + + dpcd_set_source_specific_data(link); + /* Sink may need to configure internals based on vendor, so allow some + * time before proceeding with possibly vendor specific transactions + */ + msleep(post_oui_delay); + + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_DPCD_REV, + dpcd_data, + sizeof(dpcd_data)); + if (status == DC_OK) + break; + } + + if (status != DC_OK) { + dm_error("%s: Read receiver caps dpcd data failed.\n", __func__); + return false; + } if (!is_lttpr_present) dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); - { union training_aux_rd_interval aux_rd_interval; @@ -4606,50 +4657,74 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) return DP_PANEL_MODE_DEFAULT; } -void dp_set_fec_ready(struct dc_link *link, bool ready) +enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready) { /* FEC has to be "set ready" before the link training. * The policy is to always train with FEC * if the sink supports it and leave it enabled on link. * If FEC is not supported, disable it. */ - struct link_encoder *link_enc = link->link_enc; + struct link_encoder *link_enc = NULL; + enum dc_status status = DC_OK; uint8_t fec_config = 0; + /* Access link encoder based on whether it is statically + * or dynamically assigned to a link. + */ + if (link->is_dig_mapping_flexible && + link->dc->res_pool->funcs->link_encs_assign) + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + else + link_enc = link->link_enc; + ASSERT(link_enc); + if (!dc_link_should_enable_fec(link)) - return; + return status; if (link_enc->funcs->fec_set_ready && link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { if (ready) { fec_config = 1; - if (core_link_write_dpcd(link, + status = core_link_write_dpcd(link, DP_FEC_CONFIGURATION, &fec_config, - sizeof(fec_config)) == DC_OK) { + sizeof(fec_config)); + if (status == DC_OK) { link_enc->funcs->fec_set_ready(link_enc, true); link->fec_state = dc_link_fec_ready; } else { - link->link_enc->funcs->fec_set_ready(link->link_enc, false); + link_enc->funcs->fec_set_ready(link->link_enc, false); link->fec_state = dc_link_fec_not_ready; dm_error("dpcd write failed to set fec_ready"); } } else if (link->fec_state == dc_link_fec_ready) { fec_config = 0; - core_link_write_dpcd(link, + status = core_link_write_dpcd(link, DP_FEC_CONFIGURATION, &fec_config, sizeof(fec_config)); - link->link_enc->funcs->fec_set_ready( - link->link_enc, false); + link_enc->funcs->fec_set_ready(link_enc, false); link->fec_state = dc_link_fec_not_ready; } } + + return status; } void dp_set_fec_enable(struct dc_link *link, bool enable) { - struct link_encoder *link_enc = link->link_enc; + struct link_encoder *link_enc = NULL; + + /* Access link encoder based on whether it is statically + * or dynamically assigned to a link. + */ + if (link->is_dig_mapping_flexible && + link->dc->res_pool->funcs->link_encs_assign) + link_enc = link_enc_cfg_get_link_enc_used_by_link( + link->dc->current_state, link); + else + link_enc = link->link_enc; + ASSERT(link_enc); if (!dc_link_should_enable_fec(link)) return; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c new file mode 100644 index 000000000000..fe234760a0f5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c @@ -0,0 +1,218 @@ +#include <inc/core_status.h> +#include <dc_link.h> +#include <inc/link_hwss.h> +#include <inc/link_dpcd.h> +#include "drm/drm_dp_helper.h" +#include <dc_dp_types.h> +#include "dm_helpers.h" + +#define END_ADDRESS(start, size) (start + size - 1) +#define ADDRESS_RANGE_SIZE(start, end) (end - start + 1) +struct dpcd_address_range { + uint32_t start; + uint32_t end; +}; + +static enum dc_status internal_link_read_dpcd( + struct dc_link *link, + uint32_t address, + uint8_t *data, + uint32_t size) +{ + if (!link->aux_access_disabled && + !dm_helpers_dp_read_dpcd(link->ctx, + link, address, data, size)) { + return DC_ERROR_UNEXPECTED; + } + + return DC_OK; +} + +static enum dc_status internal_link_write_dpcd( + struct dc_link *link, + uint32_t address, + const uint8_t *data, + uint32_t size) +{ + if (!link->aux_access_disabled && + !dm_helpers_dp_write_dpcd(link->ctx, + link, address, data, size)) { + return DC_ERROR_UNEXPECTED; + } + + return DC_OK; +} + +/* + * Partition the entire DPCD address space + * XXX: This partitioning must cover the entire DPCD address space, + * and must contain no gaps or overlapping address ranges. + */ +static const struct dpcd_address_range mandatory_dpcd_partitions[] = { + { 0, DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1) - 1}, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8) - 1 }, + { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 }, + /* + * The FEC registers are contiguous + */ + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7) - 1 }, + { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR8), DP_LTTPR_MAX_ADD }, + /* all remaining DPCD addresses */ + { DP_LTTPR_MAX_ADD + 1, DP_DPCD_MAX_ADD } }; + +static inline bool do_addresses_intersect_with_range( + const struct dpcd_address_range *range, + const uint32_t start_address, + const uint32_t end_address) +{ + return start_address <= range->end && end_address >= range->start; +} + +static uint32_t dpcd_get_next_partition_size(const uint32_t address, const uint32_t size) +{ + const uint32_t end_address = END_ADDRESS(address, size); + uint32_t partition_iterator = 0; + + /* + * find current partition + * this loop spins forever if partition map above is not surjective + */ + while (!do_addresses_intersect_with_range(&mandatory_dpcd_partitions[partition_iterator], + address, end_address)) + partition_iterator++; + if (end_address < mandatory_dpcd_partitions[partition_iterator].end) + return size; + return ADDRESS_RANGE_SIZE(address, mandatory_dpcd_partitions[partition_iterator].end); +} + +/* + * Ranges of DPCD addresses that must be read in a single transaction + * XXX: Do not allow any two address ranges in this array to overlap + */ +static const struct dpcd_address_range mandatory_dpcd_blocks[] = { + { DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT }}; + +/* + * extend addresses to read all mandatory blocks together + */ +static void dpcd_extend_address_range( + const uint32_t in_address, + uint8_t * const in_data, + const uint32_t in_size, + uint32_t *out_address, + uint8_t **out_data, + uint32_t *out_size) +{ + const uint32_t end_address = END_ADDRESS(in_address, in_size); + const struct dpcd_address_range *addr_range; + struct dpcd_address_range new_addr_range; + uint32_t i; + + new_addr_range.start = in_address; + new_addr_range.end = end_address; + for (i = 0; i < ARRAY_SIZE(mandatory_dpcd_blocks); i++) { + addr_range = &mandatory_dpcd_blocks[i]; + if (addr_range->start <= in_address && addr_range->end >= in_address) + new_addr_range.start = addr_range->start; + + if (addr_range->start <= end_address && addr_range->end >= end_address) + new_addr_range.end = addr_range->end; + } + *out_address = in_address; + *out_size = in_size; + *out_data = in_data; + if (new_addr_range.start != in_address || new_addr_range.end != end_address) { + *out_address = new_addr_range.start; + *out_size = ADDRESS_RANGE_SIZE(new_addr_range.start, new_addr_range.end); + *out_data = kzalloc(*out_size * sizeof(**out_data), GFP_KERNEL); + } +} + +/* + * Reduce the AUX reply down to the values the caller requested + */ +static void dpcd_reduce_address_range( + const uint32_t extended_address, + uint8_t * const extended_data, + const uint32_t extended_size, + const uint32_t reduced_address, + uint8_t * const reduced_data, + const uint32_t reduced_size) +{ + const uint32_t reduced_end_address = END_ADDRESS(reduced_address, reduced_size); + const uint32_t extended_end_address = END_ADDRESS(extended_address, extended_size); + const uint32_t offset = reduced_address - extended_address; + + if (extended_end_address == reduced_end_address && extended_address == reduced_address) + return; /* extended and reduced address ranges point to the same data */ + + memcpy(&extended_data[offset], reduced_data, reduced_size); + kfree(extended_data); +} + +enum dc_status core_link_read_dpcd( + struct dc_link *link, + uint32_t address, + uint8_t *data, + uint32_t size) +{ + uint32_t extended_address; + uint32_t partitioned_address; + uint8_t *extended_data; + uint32_t extended_size; + /* size of the remaining partitioned address space */ + uint32_t size_left_to_read; + enum dc_status status; + /* size of the next partition to be read from */ + uint32_t partition_size; + uint32_t data_index = 0; + + dpcd_extend_address_range(address, data, size, &extended_address, &extended_data, &extended_size); + partitioned_address = extended_address; + size_left_to_read = extended_size; + while (size_left_to_read) { + partition_size = dpcd_get_next_partition_size(partitioned_address, size_left_to_read); + status = internal_link_read_dpcd(link, partitioned_address, &extended_data[data_index], partition_size); + if (status != DC_OK) + break; + partitioned_address += partition_size; + data_index += partition_size; + size_left_to_read -= partition_size; + } + dpcd_reduce_address_range(extended_address, extended_data, extended_size, address, data, size); + return status; +} + +enum dc_status core_link_write_dpcd( + struct dc_link *link, + uint32_t address, + const uint8_t *data, + uint32_t size) +{ + uint32_t partition_size; + uint32_t data_index = 0; + enum dc_status status; + + while (size) { + partition_size = dpcd_get_next_partition_size(address, size); + status = internal_link_write_dpcd(link, address, &data[data_index], partition_size); + if (status != DC_OK) + break; + address += partition_size; + data_index += partition_size; + size -= partition_size; + } + return status; +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 13c5c4a34a58..9c51cd09dcf1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -16,6 +16,7 @@ #include "resource.h" #include "link_enc_cfg.h" #include "clk_mgr.h" +#include "inc/link_dpcd.h" static uint8_t convert_to_count(uint8_t lttpr_repeater_count) { @@ -47,36 +48,6 @@ static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset); } -enum dc_status core_link_read_dpcd( - struct dc_link *link, - uint32_t address, - uint8_t *data, - uint32_t size) -{ - if (!link->aux_access_disabled && - !dm_helpers_dp_read_dpcd(link->ctx, - link, address, data, size)) { - return DC_ERROR_UNEXPECTED; - } - - return DC_OK; -} - -enum dc_status core_link_write_dpcd( - struct dc_link *link, - uint32_t address, - const uint8_t *data, - uint32_t size) -{ - if (!link->aux_access_disabled && - !dm_helpers_dp_write_dpcd(link->ctx, - link, address, data, size)) { - return DC_ERROR_UNEXPECTED; - } - - return DC_OK; -} - void dp_receiver_power_ctrl(struct dc_link *link, bool on) { uint8_t state; @@ -332,7 +303,16 @@ void dp_set_hw_test_pattern( uint32_t custom_pattern_size) { struct encoder_set_dp_phy_pattern_param pattern_param = {0}; - struct link_encoder *encoder = link->link_enc; + struct link_encoder *encoder; + + /* Access link encoder based on whether it is statically + * or dynamically assigned to a link. + */ + if (link->is_dig_mapping_flexible && + link->dc->res_pool->funcs->link_encs_assign) + encoder = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + else + encoder = link->link_enc; pattern_param.dp_phy_pattern = test_pattern; pattern_param.custom_pattern = custom_pattern; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 8a158a192ec0..a6a67244a322 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -58,6 +58,7 @@ #include "dcn301/dcn301_resource.h" #include "dcn302/dcn302_resource.h" #include "dcn303/dcn303_resource.h" +#include "dcn31/dcn31_resource.h" #endif #define DC_LOGGER_INIT(logger) @@ -138,7 +139,13 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) case FAMILY_VGH: dc_version = DCN_VERSION_3_01; break; + + case FAMILY_YELLOW_CARP: + if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)) + dc_version = DCN_VERSION_3_1; + break; #endif + default: dc_version = DCE_VERSION_UNKNOWN; break; @@ -222,6 +229,9 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, case DCN_VERSION_3_03: res_pool = dcn303_create_resource_pool(init_data, dc); break; + case DCN_VERSION_3_1: + res_pool = dcn31_create_resource_pool(init_data, dc); + break; #endif default: break; @@ -429,7 +439,7 @@ bool resource_are_vblanks_synchronizable( { uint32_t base60_refresh_rates[] = {10, 20, 5}; uint8_t i; - uint8_t rr_count = sizeof(base60_refresh_rates)/sizeof(base60_refresh_rates[0]); + uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates); uint64_t frame_time_diff; if (stream1->ctx->dc->config.vblank_alignment_dto_params && @@ -611,6 +621,7 @@ static enum pixel_format convert_pixel_format_to_dalsurface( dal_pixel_format = PIXEL_FORMAT_420BPP10; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: default: dal_pixel_format = PIXEL_FORMAT_UNKNOWN; break; @@ -701,124 +712,23 @@ static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *spli } } -static void calculate_viewport(struct pipe_ctx *pipe_ctx) +/* + * This is a preliminary vp size calculation to allow us to check taps support. + * The result is completely overridden afterwards. + */ +static void calculate_viewport_size(struct pipe_ctx *pipe_ctx) { - const struct dc_plane_state *plane_state = pipe_ctx->plane_state; - const struct dc_stream_state *stream = pipe_ctx->stream; struct scaler_data *data = &pipe_ctx->plane_res.scl_data; - struct rect surf_src = plane_state->src_rect; - struct rect clip, dest; - int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 - || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; - int split_count = 0; - int split_idx = 0; - bool orthogonal_rotation, flip_y_start, flip_x_start; - - calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); - - if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE || - stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { - split_count = 0; - split_idx = 0; - } - - /* The actual clip is an intersection between stream - * source and surface clip - */ - dest = plane_state->dst_rect; - clip.x = stream->src.x > plane_state->clip_rect.x ? - stream->src.x : plane_state->clip_rect.x; - - clip.width = stream->src.x + stream->src.width < - plane_state->clip_rect.x + plane_state->clip_rect.width ? - stream->src.x + stream->src.width - clip.x : - plane_state->clip_rect.x + plane_state->clip_rect.width - clip.x ; - - clip.y = stream->src.y > plane_state->clip_rect.y ? - stream->src.y : plane_state->clip_rect.y; - - clip.height = stream->src.y + stream->src.height < - plane_state->clip_rect.y + plane_state->clip_rect.height ? - stream->src.y + stream->src.height - clip.y : - plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ; - /* - * Need to calculate how scan origin is shifted in vp space - * to correctly rotate clip and dst - */ - get_vp_scan_direction( - plane_state->rotation, - plane_state->horizontal_mirror, - &orthogonal_rotation, - &flip_y_start, - &flip_x_start); - - if (orthogonal_rotation) { - swap(clip.x, clip.y); - swap(clip.width, clip.height); - swap(dest.x, dest.y); - swap(dest.width, dest.height); - } - if (flip_x_start) { - clip.x = dest.x + dest.width - clip.x - clip.width; - dest.x = 0; - } - if (flip_y_start) { - clip.y = dest.y + dest.height - clip.y - clip.height; - dest.y = 0; - } - - /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio - * num_pixels = clip.num_pix * scl_ratio - */ - data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width; - data->viewport.width = clip.width * surf_src.width / dest.width; - - data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height; - data->viewport.height = clip.height * surf_src.height / dest.height; - - /* Handle split */ - if (split_count) { - /* extra pixels in the division remainder need to go to pipes after - * the extra pixel index minus one(epimo) defined here as: - */ - int epimo = 0; - - if (orthogonal_rotation) { - if (flip_y_start) - split_idx = split_count - split_idx; - - epimo = split_count - data->viewport.height % (split_count + 1); - - data->viewport.y += (data->viewport.height / (split_count + 1)) * split_idx; - if (split_idx > epimo) - data->viewport.y += split_idx - epimo - 1; - data->viewport.height = data->viewport.height / (split_count + 1) + (split_idx > epimo ? 1 : 0); - } else { - if (flip_x_start) - split_idx = split_count - split_idx; - - epimo = split_count - data->viewport.width % (split_count + 1); - - data->viewport.x += (data->viewport.width / (split_count + 1)) * split_idx; - if (split_idx > epimo) - data->viewport.x += split_idx - epimo - 1; - data->viewport.width = data->viewport.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); - } + data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width)); + data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height)); + data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width)); + data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height)); + if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || + pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { + swap(data->viewport.width, data->viewport.height); + swap(data->viewport_c.width, data->viewport_c.height); } - - /* Round down, compensate in init */ - data->viewport_c.x = data->viewport.x / vpc_div; - data->viewport_c.y = data->viewport.y / vpc_div; - data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; - data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; - - /* Round up, assume original video size always even dimensions */ - data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div; - data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div; - - data->viewport_unadjusted = data->viewport; - data->viewport_c_unadjusted = data->viewport_c; } static void calculate_recout(struct pipe_ctx *pipe_ctx) @@ -827,26 +737,21 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx) const struct dc_stream_state *stream = pipe_ctx->stream; struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct rect surf_clip = plane_state->clip_rect; - bool pri_split_tb = pipe_ctx->bottom_pipe && - pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state && - stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; - bool sec_split_tb = pipe_ctx->top_pipe && - pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state && - stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; - int split_count = 0; - int split_idx = 0; + bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; + int split_count, split_idx; calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); + if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) + split_idx = 0; /* * Only the leftmost ODM pipe should be offset by a nonzero distance */ - if (!pipe_ctx->prev_odm_pipe) { + if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { data->recout.x = stream->dst.x; if (stream->src.x < surf_clip.x) data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width / stream->src.width; - } else data->recout.x = 0; @@ -867,26 +772,36 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx) if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height) data->recout.height = stream->dst.y + stream->dst.height - data->recout.y; - /* Handle h & v split, handle rotation using viewport */ - if (sec_split_tb) { - data->recout.y += data->recout.height / 2; - /* Floor primary pipe, ceil 2ndary pipe */ - data->recout.height = (data->recout.height + 1) / 2; - } else if (pri_split_tb) + /* Handle h & v split */ + if (split_tb) { + ASSERT(data->recout.height % 2 == 0); data->recout.height /= 2; - else if (split_count) { - /* extra pixels in the division remainder need to go to pipes after - * the extra pixel index minus one(epimo) defined here as: - */ - int epimo = split_count - data->recout.width % (split_count + 1); - - /*no recout offset due to odm */ + } else if (split_count) { if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) { + /* extra pixels in the division remainder need to go to pipes after + * the extra pixel index minus one(epimo) defined here as: + */ + int epimo = split_count - data->recout.width % (split_count + 1); + data->recout.x += (data->recout.width / (split_count + 1)) * split_idx; if (split_idx > epimo) data->recout.x += split_idx - epimo - 1; + ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0); + data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); + } else { + /* odm */ + if (split_idx == split_count) { + /* rightmost pipe is the remainder recout */ + data->recout.width -= data->h_active * split_count - data->recout.x; + + /* ODM combine cases with MPO we can get negative widths */ + if (data->recout.width < 0) + data->recout.width = 0; + + data->recout.x = 0; + } else + data->recout.width = data->h_active - data->recout.x; } - data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); } } @@ -940,9 +855,15 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); } -static inline void adjust_vp_and_init_for_seamless_clip( + +/* + * We completely calculate vp offset, size and inits here based entirely on scaling + * ratios and recout for pixel perfect pipe combine. + */ +static void calculate_init_and_vp( bool flip_scan_dir, - int recout_skip, + int recout_offset_within_recout_full, + int recout_size, int src_size, int taps, struct fixed31_32 ratio, @@ -950,91 +871,87 @@ static inline void adjust_vp_and_init_for_seamless_clip( int *vp_offset, int *vp_size) { - if (!flip_scan_dir) { - /* Adjust for viewport end clip-off */ - if ((*vp_offset + *vp_size) < src_size) { - int vp_clip = src_size - *vp_size - *vp_offset; - int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); + struct fixed31_32 temp; + int int_part; - int_part = int_part > 0 ? int_part : 0; - *vp_size += int_part < vp_clip ? int_part : vp_clip; - } - - /* Adjust for non-0 viewport offset */ - if (*vp_offset) { - int int_part; - - *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); - int_part = dc_fixpt_floor(*init) - *vp_offset; - if (int_part < taps) { - int int_adj = *vp_offset >= (taps - int_part) ? - (taps - int_part) : *vp_offset; - *vp_offset -= int_adj; - *vp_size += int_adj; - int_part += int_adj; - } else if (int_part > taps) { - *vp_offset += int_part - taps; - *vp_size -= int_part - taps; - int_part = taps; - } - init->value &= 0xffffffff; - *init = dc_fixpt_add_int(*init, int_part); - } - } else { - /* Adjust for non-0 viewport offset */ - if (*vp_offset) { - int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); - - int_part = int_part > 0 ? int_part : 0; - *vp_size += int_part < *vp_offset ? int_part : *vp_offset; - *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset; - } - - /* Adjust for viewport end clip-off */ - if ((*vp_offset + *vp_size) < src_size) { - int int_part; - int end_offset = src_size - *vp_offset - *vp_size; - - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, takning into account scan direction - */ - int_part = dc_fixpt_floor(*init) - end_offset; - if (int_part < taps) { - int int_adj = end_offset >= (taps - int_part) ? - (taps - int_part) : end_offset; - *vp_size += int_adj; - int_part += int_adj; - } else if (int_part > taps) { - *vp_size += int_part - taps; - int_part = taps; - } - init->value &= 0xffffffff; - *init = dc_fixpt_add_int(*init, int_part); - } + /* + * First of the taps starts sampling pixel number <init_int_part> corresponding to recout + * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on. + * All following calculations are based on this logic. + * + * Init calculated according to formula: + * init = (scaling_ratio + number_of_taps + 1) / 2 + * init_bot = init + scaling_ratio + * to get pixel perfect combine add the fraction from calculating vp offset + */ + temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full); + *vp_offset = dc_fixpt_floor(temp); + temp.value &= 0xffffffff; + *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int( + dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19); + /* + * If viewport has non 0 offset and there are more taps than covered by init then + * we should decrease the offset and increase init so we are never sampling + * outside of viewport. + */ + int_part = dc_fixpt_floor(*init); + if (int_part < taps) { + int_part = taps - int_part; + if (int_part > *vp_offset) + int_part = *vp_offset; + *vp_offset -= int_part; + *init = dc_fixpt_add_int(*init, int_part); } + /* + * If taps are sampling outside of viewport at end of recout and there are more pixels + * available in the surface we should increase the viewport size, regardless set vp to + * only what is used. + */ + temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1)); + *vp_size = dc_fixpt_floor(temp); + if (*vp_size + *vp_offset > src_size) + *vp_size = src_size - *vp_offset; + + /* We did all the math assuming we are scanning same direction as display does, + * however mirror/rotation changes how vp scans vs how it is offset. If scan direction + * is flipped we simply need to calculate offset from the other side of plane. + * Note that outside of viewport all scaling hardware works in recout space. + */ + if (flip_scan_dir) + *vp_offset = src_size - *vp_offset - *vp_size; } -static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) +static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; const struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe = pipe_ctx; struct scaler_data *data = &pipe_ctx->plane_res.scl_data; - struct rect src = pipe_ctx->plane_state->src_rect; - int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v; + struct rect src = plane_state->src_rect; int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 - || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; + || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; + int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y; bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; - int odm_idx = 0; + + calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); + /* + * recout full is what the recout would have been if we didnt clip + * the source plane at all. We only care about left(ro_lb) and top(ro_tb) + * offsets of recout within recout full because those are the directions + * we scan from and therefore the only ones that affect inits. + */ + recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) + * stream->dst.width / stream->src.width; + recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) + * stream->dst.height / stream->src.height; + if (pipe_ctx->prev_odm_pipe && split_idx) + ro_lb = data->h_active * split_idx - recout_full_x; + else + ro_lb = data->recout.x - recout_full_x; + ro_tb = data->recout.y - recout_full_y; + ASSERT(ro_lb >= 0 && ro_tb >= 0); /* - * Need to calculate the scan direction for viewport to make adjustments + * Work in recout rotation since that requires less transformations */ get_vp_scan_direction( plane_state->rotation, @@ -1043,145 +960,62 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) &flip_vert_scan_dir, &flip_horz_scan_dir); - /* Calculate src rect rotation adjusted to recout space */ - surf_size_h = src.x + src.width; - surf_size_v = src.y + src.height; - if (flip_horz_scan_dir) - src.x = 0; - if (flip_vert_scan_dir) - src.y = 0; if (orthogonal_rotation) { - swap(src.x, src.y); swap(src.width, src.height); + swap(flip_vert_scan_dir, flip_horz_scan_dir); } - /*modified recout_skip_h calculation due to odm having no recout offset*/ - while (odm_pipe->prev_odm_pipe) { - odm_idx++; - odm_pipe = odm_pipe->prev_odm_pipe; - } - /*odm_pipe is the leftmost pipe in the ODM group*/ - recout_skip_h = odm_idx * data->recout.width; - - /* Recout matching initial vp offset = recout_offset - (stream dst offset + - * ((surf dst offset - stream src offset) * 1/ stream scaling ratio) - * - (surf surf_src offset * 1/ full scl ratio)) - */ - recout_skip_h += odm_pipe->plane_res.scl_data.recout.x - - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x) - * stream->dst.width / stream->src.width - - src.x * plane_state->dst_rect.width / src.width - * stream->dst.width / stream->src.width); - - - recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y) - * stream->dst.height / stream->src.height - - src.y * plane_state->dst_rect.height / src.height - * stream->dst.height / stream->src.height); - if (orthogonal_rotation) - swap(recout_skip_h, recout_skip_v); - /* - * Init calculated according to formula: - * init = (scaling_ratio + number_of_taps + 1) / 2 - * init_bot = init + scaling_ratio - * init_c = init + truncated_vp_c_offset(from calculate viewport) - */ - data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); - - data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); - - data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); - - data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); - - /* - * Taps, inits and scaling ratios are in recout space need to rotate - * to viewport rotation before adjustment - */ - adjust_vp_and_init_for_seamless_clip( + calculate_init_and_vp( flip_horz_scan_dir, - recout_skip_h, - surf_size_h, - orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps, - orthogonal_rotation ? data->ratios.vert : data->ratios.horz, - orthogonal_rotation ? &data->inits.v : &data->inits.h, + ro_lb, + data->recout.width, + src.width, + data->taps.h_taps, + data->ratios.horz, + &data->inits.h, &data->viewport.x, &data->viewport.width); - adjust_vp_and_init_for_seamless_clip( + calculate_init_and_vp( flip_horz_scan_dir, - recout_skip_h, - surf_size_h / vpc_div, - orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c, - orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c, - orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c, + ro_lb, + data->recout.width, + src.width / vpc_div, + data->taps.h_taps_c, + data->ratios.horz_c, + &data->inits.h_c, &data->viewport_c.x, &data->viewport_c.width); - adjust_vp_and_init_for_seamless_clip( + calculate_init_and_vp( flip_vert_scan_dir, - recout_skip_v, - surf_size_v, - orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps, - orthogonal_rotation ? data->ratios.horz : data->ratios.vert, - orthogonal_rotation ? &data->inits.h : &data->inits.v, + ro_tb, + data->recout.height, + src.height, + data->taps.v_taps, + data->ratios.vert, + &data->inits.v, &data->viewport.y, &data->viewport.height); - adjust_vp_and_init_for_seamless_clip( + calculate_init_and_vp( flip_vert_scan_dir, - recout_skip_v, - surf_size_v / vpc_div, - orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c, - orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c, - orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c, + ro_tb, + data->recout.height, + src.height / vpc_div, + data->taps.v_taps_c, + data->ratios.vert_c, + &data->inits.v_c, &data->viewport_c.y, &data->viewport_c.height); - - /* Interlaced inits based on final vert inits */ - data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert); - data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); - -} - -/* - * When handling 270 rotation in mixed SLS mode, we have - * stream->timing.h_border_left that is non zero. If we are doing - * pipe-splitting, this h_border_left value gets added to recout.x and when it - * calls calculate_inits_and_adj_vp() and - * adjust_vp_and_init_for_seamless_clip(), it can cause viewport.height for a - * pipe to be incorrect. - * - * To fix this, instead of using stream->timing.h_border_left, we can use - * stream->dst.x to represent the border instead. So we will set h_border_left - * to 0 and shift the appropriate amount in stream->dst.x. We will then - * perform all calculations in resource_build_scaling_params() based on this - * and then restore the h_border_left and stream->dst.x to their original - * values. - * - * shift_border_left_to_dst() will shift the amount of h_border_left to - * stream->dst.x and set h_border_left to 0. restore_border_left_from_dst() - * will restore h_border_left and stream->dst.x back to their original values - * We also need to make sure pipe_ctx->plane_res.scl_data.h_active uses the - * original h_border_left value in its calculation. - */ -static int shift_border_left_to_dst(struct pipe_ctx *pipe_ctx) -{ - int store_h_border_left = pipe_ctx->stream->timing.h_border_left; - - if (store_h_border_left) { - pipe_ctx->stream->timing.h_border_left = 0; - pipe_ctx->stream->dst.x += store_h_border_left; + if (orthogonal_rotation) { + swap(data->viewport.x, data->viewport.y); + swap(data->viewport.width, data->viewport.height); + swap(data->viewport_c.x, data->viewport_c.y); + swap(data->viewport_c.width, data->viewport_c.height); } - return store_h_border_left; -} - -static void restore_border_left_from_dst(struct pipe_ctx *pipe_ctx, - int store_h_border_left) -{ - pipe_ctx->stream->dst.x -= store_h_border_left; - pipe_ctx->stream->timing.h_border_left = store_h_border_left; + data->viewport.x += src.x; + data->viewport.y += src.y; + ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0); + data->viewport_c.x += src.x / vpc_div; + data->viewport_c.y += src.y / vpc_div; } bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) @@ -1189,48 +1023,52 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) const struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; bool res = false; - int store_h_border_left = shift_border_left_to_dst(pipe_ctx); DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); - /* Important: scaling ratio calculation requires pixel format, - * lb depth calculation requires recout and taps require scaling ratios. - * Inits require viewport, taps, ratios and recout of split pipe - */ + pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( pipe_ctx->plane_state->format); - calculate_scaling_ratios(pipe_ctx); - - calculate_viewport(pipe_ctx); - - if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || - pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) { - if (store_h_border_left) { - restore_border_left_from_dst(pipe_ctx, - store_h_border_left); - } - return false; - } - - calculate_recout(pipe_ctx); - - /** - * Setting line buffer pixel depth to 24bpp yields banding - * on certain displays, such as the Sharp 4k + /* Timing borders are part of vactive that we are also supposed to skip in addition + * to any stream dst offset. Since dm logic assumes dst is in addressable + * space we need to add the the left and top borders to dst offsets temporarily. + * TODO: fix in DM, stream dst is supposed to be in vactive */ - pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; - - pipe_ctx->plane_res.scl_data.recout.x += timing->h_border_left; - pipe_ctx->plane_res.scl_data.recout.y += timing->v_border_top; + pipe_ctx->stream->dst.x += timing->h_border_left; + pipe_ctx->stream->dst.y += timing->v_border_top; + /* Calculate H and V active size */ pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + - store_h_border_left + timing->h_border_right; + timing->h_border_left + timing->h_border_right; pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + timing->v_border_top + timing->v_border_bottom; if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; - /* Taps calculations */ + /* depends on h_active */ + calculate_recout(pipe_ctx); + /* depends on pixel format */ + calculate_scaling_ratios(pipe_ctx); + /* depends on scaling ratios and recout, does not calculate offset yet */ + calculate_viewport_size(pipe_ctx); + + /* + * LB calculations depend on vp size, h/v_active and scaling ratios + * Setting line buffer pixel depth to 24bpp yields banding + * on certain displays, such as the Sharp 4k. 36bpp is needed + * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and + * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc + * precision on at least DCN display engines. However, at least + * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth, + * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3 + * did not show such problems, so this seems to be the exception. + */ + if (plane_state->ctx->dce_version != DCE_VERSION_11_0) + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; + else + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; + if (pipe_ctx->plane_res.xfm != NULL) res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); @@ -1257,9 +1095,31 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) &plane_state->scaling_quality); } + /* + * Depends on recout, scaling ratios, h_active and taps + * May need to re-check lb size after this in some obscure scenario + */ if (res) - /* May need to re-check lb size after this in some obscure scenario */ - calculate_inits_and_adj_vp(pipe_ctx); + calculate_inits_and_viewports(pipe_ctx); + + /* + * Handle side by side and top bottom 3d recout offsets after vp calculation + * since 3d is special and needs to calculate vp as if there is no recout offset + * This may break with rotation, good thing we aren't mixing hw rotation and 3d + */ + if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) { + ASSERT(plane_state->rotation == ROTATION_ANGLE_0 || + (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && + pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE)); + if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) + pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; + else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) + pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; + } + + if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || + pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) + res = false; DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n" "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n", @@ -1288,8 +1148,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) plane_state->clip_rect.x, plane_state->clip_rect.y); - if (store_h_border_left) - restore_border_left_from_dst(pipe_ctx, store_h_border_left); + pipe_ctx->stream->dst.x -= timing->h_border_left; + pipe_ctx->stream->dst.y -= timing->v_border_top; return res; } @@ -2276,6 +2136,16 @@ enum dc_status dc_validate_global_state( if (!new_ctx) return DC_ERROR_UNEXPECTED; +#if defined(CONFIG_DRM_AMD_DC_DCN) + + /* + * Update link encoder to stream assignment. + * TODO: Split out reason allocation from validation. + */ + if (dc->res_pool->funcs->link_encs_assign) + dc->res_pool->funcs->link_encs_assign( + dc, new_ctx, new_ctx->streams, new_ctx->stream_count); +#endif if (dc->res_pool->funcs->validate_global) { result = dc->res_pool->funcs->validate_global(dc, new_ctx); @@ -3046,6 +2916,7 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format) #endif return 32; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: return 64; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 25fa712a7847..45931ee14a6e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -294,6 +294,7 @@ bool dc_stream_set_cursor_attributes( stream->cursor_attributes = *attributes; #if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_restore(dc); /* disable idle optimizations while updating cursor */ if (dc->idle_optimizations_allowed) { dc_allow_idle_optimizations(dc, false); @@ -355,6 +356,7 @@ bool dc_stream_set_cursor_position( dc = stream->ctx->dc; res_ctx = &dc->current_state->res_ctx; #if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_restore(dc); /* disable idle optimizations if enabling cursor */ if (dc->idle_optimizations_allowed && !stream->cursor_position.enable && position->enable) { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7da5e7a2e88d..5101a4f8f69f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -45,7 +45,7 @@ /* forward declaration */ struct aux_payload; -#define DC_VER "3.2.136" +#define DC_VER "3.2.141" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -303,6 +303,7 @@ struct dc_config { bool multi_mon_pp_mclk_switch; bool disable_dmcu; bool enable_4to1MPC; + bool allow_edp_hotplug_detection; #if defined(CONFIG_DRM_AMD_DC_DCN) bool clamp_min_dcfclk; #endif @@ -318,6 +319,7 @@ enum visual_confirm { VISUAL_CONFIRM_HDR = 2, VISUAL_CONFIRM_MPCTREE = 4, VISUAL_CONFIRM_PSR = 5, + VISUAL_CONFIRM_SWIZZLE = 9, }; enum dcc_option { @@ -350,6 +352,13 @@ enum dcn_pwr_state { DCN_PWR_STATE_LOW_POWER = 3, }; +#if defined(CONFIG_DRM_AMD_DC_DCN) +enum dcn_z9_support_state { + DCN_Z9_SUPPORT_UNKNOWN, + DCN_Z9_SUPPORT_ALLOW, + DCN_Z9_SUPPORT_DISALLOW, +}; +#endif /* * For any clocks that may differ per pipe * only the max is stored in this structure @@ -367,6 +376,10 @@ struct dc_clocks { int phyclk_khz; int dramclk_khz; bool p_state_change_support; +#if defined(CONFIG_DRM_AMD_DC_DCN) + enum dcn_z9_support_state z9_support; + bool dtbclk_en; +#endif enum dcn_pwr_state pwr_state; /* * Elements below are not compared for the purposes of @@ -433,6 +446,7 @@ struct dc_bw_validation_profile { union mem_low_power_enable_options { struct { + bool vga: 1; bool i2c: 1; bool dmcu: 1; bool dscl: 1; @@ -487,6 +501,9 @@ struct dc_debug_options { bool disable_pplib_clock_request; bool disable_clock_gate; bool disable_mem_low_power; +#if defined(CONFIG_DRM_AMD_DC_DCN) + bool pstate_enabled; +#endif bool disable_dmcu; bool disable_psr; bool force_abm_enable; @@ -505,6 +522,7 @@ struct dc_debug_options { unsigned int force_odm_combine; //bit vector based on otg inst #if defined(CONFIG_DRM_AMD_DC_DCN) unsigned int force_odm_combine_4to1; //bit vector based on otg inst + bool disable_z9_mpc; #endif unsigned int force_fclk_khz; bool enable_tri_buf; @@ -547,6 +565,10 @@ struct dc_debug_options { bool force_enable_edp_fec; /* FEC/PSR1 sequence enable delay in 100us */ uint8_t fec_enable_delay_in100us; +#if defined(CONFIG_DRM_AMD_DC_DCN) + bool disable_z10; + bool enable_sw_cntl_psr; +#endif }; struct dc_debug_data { @@ -571,6 +593,9 @@ struct dc_phy_addr_space_config { uint64_t page_table_start_addr; uint64_t page_table_end_addr; uint64_t page_table_base_addr; +#if defined(CONFIG_DRM_AMD_DC_DCN) + bool base_addr_is_mc_addr; +#endif } gart_config; bool valid; @@ -1069,8 +1094,6 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); */ bool dc_commit_state(struct dc *dc, struct dc_state *context); -void dc_power_down_on_boot(struct dc *dc); - struct dc_state *dc_create_state(struct dc *dc); struct dc_state *dc_copy_state(struct dc_state *src_ctx); void dc_retain_state(struct dc_state *context); @@ -1310,6 +1333,9 @@ void dc_hardware_release(struct dc *dc); #endif bool dc_set_psr_allow_active(struct dc *dc, bool enable); +#if defined(CONFIG_DRM_AMD_DC_DCN) +void dc_z10_restore(struct dc *dc); +#endif bool dc_enable_dmub_notifications(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index c5dc3a947020..360f3199ea6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -86,6 +86,7 @@ void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, error: DC_ERROR("Error queuing DMUB command: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); } void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) @@ -95,8 +96,10 @@ void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) enum dmub_status status; status = dmub_srv_cmd_execute(dmub); - if (status != DMUB_STATUS_OK) + if (status != DMUB_STATUS_OK) { DC_ERROR("Error starting DMUB execution: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } } void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) @@ -106,8 +109,19 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) enum dmub_status status; status = dmub_srv_wait_for_idle(dmub, 100000); - if (status != DMUB_STATUS_OK) + if (status != DMUB_STATUS_OK) { DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } +} + +void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, + union dmub_inbox0_data_register data) +{ + struct dmub_srv *dmub = dmub_srv->dmub; + if (dmub->hw_funcs.send_inbox0_cmd) + dmub->hw_funcs.send_inbox0_cmd(dmub, data); + // TODO: Add wait command -- poll register for ACK } bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd) @@ -172,6 +186,28 @@ bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, stream_mask, timeout) == DMUB_STATUS_OK; } +bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub; + struct dc_context *dc_ctx; + union dmub_fw_boot_status boot_status; + enum dmub_status status; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return false; + + dmub = dc_dmub_srv->dmub; + dc_ctx = dc_dmub_srv->ctx; + + status = dmub_srv_get_fw_boot_status(dmub, &boot_status); + if (status != DMUB_STATUS_OK) { + DC_ERROR("Error querying DMUB boot status: error=%d\n", status); + return false; + } + + return boot_status.bits.restore_required; +} + bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry) { struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; @@ -182,3 +218,94 @@ void dc_dmub_trace_event_control(struct dc *dc, bool enable) { dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable); } + +bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data) +{ + if (!dc_dmub_srv || !dc_dmub_srv->dmub || !diag_data) + return false; + return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub, diag_data); +} + +void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_diagnostic_data diag_data = {0}; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) { + DC_LOG_ERROR("%s: invalid parameters.", __func__); + return; + } + + if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) { + DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__); + return; + } + + DC_LOG_DEBUG( + "DMCUB STATE\n" + " dmcub_version : %08x\n" + " scratch [0] : %08x\n" + " scratch [1] : %08x\n" + " scratch [2] : %08x\n" + " scratch [3] : %08x\n" + " scratch [4] : %08x\n" + " scratch [5] : %08x\n" + " scratch [6] : %08x\n" + " scratch [7] : %08x\n" + " scratch [8] : %08x\n" + " scratch [9] : %08x\n" + " scratch [10] : %08x\n" + " scratch [11] : %08x\n" + " scratch [12] : %08x\n" + " scratch [13] : %08x\n" + " scratch [14] : %08x\n" + " scratch [15] : %08x\n" + " pc : %08x\n" + " unk_fault_addr : %08x\n" + " inst_fault_addr : %08x\n" + " data_fault_addr : %08x\n" + " inbox1_rptr : %08x\n" + " inbox1_wptr : %08x\n" + " inbox1_size : %08x\n" + " inbox0_rptr : %08x\n" + " inbox0_wptr : %08x\n" + " inbox0_size : %08x\n" + " is_enabled : %d\n" + " is_soft_reset : %d\n" + " is_secure_reset : %d\n" + " is_traceport_en : %d\n" + " is_cw0_en : %d\n" + " is_cw6_en : %d\n", + diag_data.dmcub_version, + diag_data.scratch[0], + diag_data.scratch[1], + diag_data.scratch[2], + diag_data.scratch[3], + diag_data.scratch[4], + diag_data.scratch[5], + diag_data.scratch[6], + diag_data.scratch[7], + diag_data.scratch[8], + diag_data.scratch[9], + diag_data.scratch[10], + diag_data.scratch[11], + diag_data.scratch[12], + diag_data.scratch[13], + diag_data.scratch[14], + diag_data.scratch[15], + diag_data.pc, + diag_data.undefined_address_fault_addr, + diag_data.inst_fetch_fault_addr, + diag_data.data_write_fault_addr, + diag_data.inbox1_rptr, + diag_data.inbox1_wptr, + diag_data.inbox1_size, + diag_data.inbox0_rptr, + diag_data.inbox0_wptr, + diag_data.inbox0_size, + diag_data.is_dmcub_enabled, + diag_data.is_dmcub_soft_reset, + diag_data.is_dmcub_secure_reset, + diag_data.is_traceport_en, + diag_data.is_cw0_enabled, + diag_data.is_cw6_enabled); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 338f776990db..3e35eee7188c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -62,8 +62,16 @@ bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, unsigned int stream_mask); +bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv); + bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry); void dc_dmub_trace_event_control(struct dc *dc, bool enable); +void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, union dmub_inbox0_data_register data); + +bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *dmub_oca); + +void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv); + #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 04957a9efab2..52355fe6994c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -182,6 +182,8 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS, /*64 bpp */ SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616, + /*swapped*/ + SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616, /*float*/ SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F, /*swaped & float*/ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index c871923e7db0..83845d006c54 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -216,6 +216,23 @@ static inline void get_edp_links(const struct dc *dc, } } +static inline bool dc_get_edp_link_panel_inst(const struct dc *dc, + const struct dc_link *link, + unsigned int *inst_out) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + int edp_num; + + if (link->connector_signal != SIGNAL_TYPE_EDP) + return false; + get_edp_links(dc, edp_links, &edp_num); + if ((edp_num > 1) && (link->link_index > edp_links[0]->link_index)) + *inst_out = 1; + else + *inst_out = 0; + return true; +} + /* Set backlight level of an embedded panel (eDP, LVDS). * backlight_pwm_u16_16 is unsigned 32 bit with 16 bit integer * and 16 bit fractional, where 1.0 is max backlight value. @@ -316,7 +333,7 @@ bool dc_link_dp_perform_link_training_skip_aux( enum link_training_result dc_link_dp_perform_link_training( struct dc_link *link, - const struct dc_link_settings *link_setting, + const struct dc_link_settings *link_settings, bool skip_video_pattern); bool dc_link_dp_sync_lt_begin(struct dc_link *link); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 13dae7238a58..b8ebc1f09538 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -179,6 +179,9 @@ struct dc_stream_state { bool use_vsc_sdp_for_colorimetry; bool ignore_msa_timing_param; + + bool freesync_on_desktop; + bool converter_disable_audio; uint8_t qs_bit; uint8_t qy_bit; @@ -462,6 +465,10 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state *stream, struct dc_crtc_timing_adjust *adjust); +bool dc_stream_get_last_used_drr_vtotal(struct dc *dc, + struct dc_stream_state *stream, + uint32_t *refresh_rate); + bool dc_stream_get_crtc_position(struct dc *dc, struct dc_stream_state **stream, int num_streams, diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 535da8db70b6..8016e22114ce 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -271,11 +271,6 @@ struct dc_edid_caps { struct dc_panel_patch panel_patch; }; -struct view { - uint32_t width; - uint32_t height; -}; - struct dc_mode_flags { /* note: part of refresh rate flag*/ uint32_t INTERLACE :1; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index 83d97dfe328f..2fb88e54a4bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -615,7 +615,8 @@ int dce_aux_transfer_dmub_raw(struct ddc_service *ddc, } #define AUX_MAX_RETRIES 7 -#define AUX_MAX_DEFER_RETRIES 7 +#define AUX_MIN_DEFER_RETRIES 7 +#define AUX_MAX_DEFER_TIMEOUT_MS 50 #define AUX_MAX_I2C_DEFER_RETRIES 7 #define AUX_MAX_INVALID_REPLY_RETRIES 2 #define AUX_MAX_TIMEOUT_RETRIES 3 @@ -628,6 +629,10 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, bool payload_reply = true; enum aux_return_code_type operation_result; bool retry_on_defer = false; + struct ddc *ddc_pin = ddc->ddc_pin; + struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine); + uint32_t defer_time_in_ms = 0; int aux_ack_retries = 0, aux_defer_retries = 0, @@ -660,19 +665,27 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, break; case AUX_TRANSACTION_REPLY_AUX_DEFER: + /* polling_timeout_period is in us */ + defer_time_in_ms += aux110->polling_timeout_period / 1000; + ++aux_defer_retries; + fallthrough; case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: retry_on_defer = true; fallthrough; case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: - if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) { + if (aux_defer_retries >= AUX_MIN_DEFER_RETRIES + && defer_time_in_ms >= AUX_MAX_DEFER_TIMEOUT_MS) { goto fail; } else { if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) || (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) { - if (payload->defer_delay > 1) + if (payload->defer_delay > 1) { msleep(payload->defer_delay); - else if (payload->defer_delay <= 1) + defer_time_in_ms += payload->defer_delay; + } else if (payload->defer_delay <= 1) { udelay(payload->defer_delay * 1000); + defer_time_in_ms += payload->defer_delay; + } } } break; @@ -701,7 +714,7 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, // Check whether a DEFER had occurred before the timeout. // If so, treat timeout as a DEFER. if (retry_on_defer) { - if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) + if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES) goto fail; else if (payload->defer_delay > 0) msleep(payload->defer_delay); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 0db1bad7a93c..df6539e4c730 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -635,6 +635,7 @@ struct dce_hwseq_registers { uint32_t HPO_TOP_CLOCK_CONTROL; uint32_t ODM_MEM_PWR_CTRL3; uint32_t DMU_MEM_PWR_CNTL; + uint32_t MMHUBBUB_MEM_PWR_CNTL; }; /* set field name */ #define HWS_SF(blk_name, reg_name, field_name, post_fix)\ @@ -875,7 +876,8 @@ struct dce_hwseq_registers { HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh) + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) #define HWSEQ_DCN301_MASK_SH_LIST(mask_sh)\ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ @@ -1092,7 +1094,8 @@ struct dce_hwseq_registers { type AZALIA_AUDIO_DTO_MODULE; \ type ODM_MEM_UNASSIGNED_PWR_MODE; \ type ODM_MEM_VBLANK_PWR_MODE; \ - type DMCU_ERAM_MEM_PWR_FORCE; + type DMCU_ERAM_MEM_PWR_FORCE; \ + type VGA_MEM_PWR_FORCE; #define HWSEQ_DCN3_REG_FIELD_LIST(type) \ type HPO_HDMISTREAMCLK_GATE_DIS; @@ -1103,11 +1106,18 @@ struct dce_hwseq_registers { type PANEL_DIGON_OVRD;\ type PANEL_PWRSEQ_TARGET_STATE_R; +#define HWSEQ_DCN31_REG_FIELD_LIST(type) \ + type DOMAIN_POWER_FORCEON;\ + type DOMAIN_POWER_GATE;\ + type DOMAIN_PGFSM_PWR_STATUS;\ + type HPO_HDMISTREAMCLK_G_GATE_DIS; + struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) HWSEQ_DCN_REG_FIELD_LIST(uint8_t) HWSEQ_DCN3_REG_FIELD_LIST(uint8_t) HWSEQ_DCN301_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN31_REG_FIELD_LIST(uint8_t) }; struct dce_hwseq_mask { @@ -1115,6 +1125,7 @@ struct dce_hwseq_mask { HWSEQ_DCN_REG_FIELD_LIST(uint32_t) HWSEQ_DCN3_REG_FIELD_LIST(uint32_t) HWSEQ_DCN301_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN31_REG_FIELD_LIST(uint32_t) }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c index a524f471e0d7..6d1b01c267b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c @@ -264,18 +264,25 @@ static void set_speed( struct dce_i2c_hw *dce_i2c_hw, uint32_t speed) { - uint32_t xtal_ref_div = 0; + uint32_t xtal_ref_div = 0, ref_base_div = 0; uint32_t prescale = 0; + uint32_t i2c_ref_clock = 0; if (speed == 0) return; - REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div); + REG_GET_2(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, &ref_base_div, + XTAL_REF_DIV, &xtal_ref_div); if (xtal_ref_div == 0) xtal_ref_div = 2; - prescale = ((dce_i2c_hw->reference_frequency * 2) / xtal_ref_div) / speed; + if (ref_base_div == 0) + i2c_ref_clock = (dce_i2c_hw->reference_frequency * 2); + else + i2c_ref_clock = ref_base_div * 1000; + + prescale = (i2c_ref_clock / xtal_ref_div) / speed; if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL) REG_UPDATE_N(SPEED, 3, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h index 2309f2bb162c..3f45ecd189a2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h @@ -139,6 +139,7 @@ enum { I2C_SF(DC_I2C_DATA, DC_I2C_INDEX, mask_sh),\ I2C_SF(DC_I2C_DATA, DC_I2C_INDEX_WRITE, mask_sh),\ I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh),\ + I2C_SF(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, mask_sh),\ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, mask_sh) #define I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh)\ @@ -182,6 +183,7 @@ struct dce_i2c_shift { uint8_t DC_I2C_INDEX; uint8_t DC_I2C_INDEX_WRITE; uint8_t XTAL_REF_DIV; + uint8_t MICROSECOND_TIME_BASE_DIV; uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH; uint8_t DC_I2C_REG_RW_CNTL_STATUS; uint8_t I2C_LIGHT_SLEEP_FORCE; @@ -225,6 +227,7 @@ struct dce_i2c_mask { uint32_t DC_I2C_INDEX; uint32_t DC_I2C_INDEX_WRITE; uint32_t XTAL_REF_DIV; + uint32_t MICROSECOND_TIME_BASE_DIV; uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH; uint32_t DC_I2C_REG_RW_CNTL_STATUS; uint32_t I2C_LIGHT_SLEEP_FORCE; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index 79a6f261a0da..4cdd4dacb761 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -566,6 +566,7 @@ static void program_grph_pixel_format( * should problem swap endian*/ format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS || + format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { /* ABGR formats */ red_xbar = 2; @@ -606,6 +607,7 @@ static void program_grph_pixel_format( fallthrough; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: /* shouldn't this get float too? */ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: grph_depth = 3; grph_format = 0; break; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h index 23db5c72f07e..f98400efdd9b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h @@ -181,7 +181,6 @@ struct dce_mem_input_registers { SFB(blk, GRPH_ENABLE, GRPH_ENABLE, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_DEPTH, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_FORMAT, mask_sh),\ - SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ SFB(blk, GRPH_X_START, GRPH_X_START, mask_sh),\ SFB(blk, GRPH_Y_START, GRPH_Y_START, mask_sh),\ SFB(blk, GRPH_X_END, GRPH_X_END, mask_sh),\ @@ -207,7 +206,6 @@ struct dce_mem_input_registers { SFB(blk, GRPH_ENABLE, GRPH_ENABLE, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_DEPTH, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_FORMAT, mask_sh),\ - SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ SFB(blk, GRPH_X_START, GRPH_X_START, mask_sh),\ SFB(blk, GRPH_Y_START, GRPH_Y_START, mask_sh),\ SFB(blk, GRPH_X_END, GRPH_X_END, mask_sh),\ @@ -299,6 +297,7 @@ struct dce_mem_input_registers { MI_DCP_PTE_MASK_SH_LIST(mask_sh, ) #define MI_GFX9_TILE_MASK_SH_LIST(mask_sh, blk)\ + SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_SW_MODE, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_SE_ENABLE, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_NUM_SHADER_ENGINES, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index 151dc7bf6d23..d9fd4ec60588 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -794,7 +794,7 @@ static void program_bit_depth_reduction( enum dcp_out_trunc_round_mode trunc_mode; bool spatial_dither_enable; - ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */ + ASSERT(depth <= COLOR_DEPTH_121212); /* Invalid clamp bit depth */ spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED; /* Default to 12 bit truncation without rounding */ @@ -854,7 +854,7 @@ static void dce60_program_bit_depth_reduction( enum dcp_out_trunc_round_mode trunc_mode; bool spatial_dither_enable; - ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */ + ASSERT(depth <= COLOR_DEPTH_121212); /* Invalid clamp bit depth */ spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED; /* Default to 12 bit truncation without rounding */ @@ -1647,7 +1647,8 @@ void dce_transform_construct( xfm_dce->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ @@ -1675,7 +1676,8 @@ void dce60_transform_construct( xfm_dce->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c index 6939ca2e8212..54a1408c8015 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -172,16 +172,12 @@ static bool dmub_abm_set_level(struct abm *abm, uint32_t level) static bool dmub_abm_init_config(struct abm *abm, const char *src, - unsigned int bytes) + unsigned int bytes, + unsigned int inst) { union dmub_rb_cmd cmd; struct dc_context *dc = abm->ctx; - uint32_t edp_id_count = dc->dc_edp_id_count; - int i; - uint8_t panel_mask = 0; - - for (i = 0; i < edp_id_count; i++) - panel_mask |= 0x01 << i; + uint8_t panel_mask = 0x01 << inst; // TODO: Optimize by only reading back final 4 bytes dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index c97ee5abc0ef..9baf8ca0a920 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -52,6 +52,14 @@ void dmub_hw_lock_mgr_cmd(struct dc_dmub_srv *dmub_srv, dc_dmub_srv_wait_idle(dmub_srv); } +void dmub_hw_lock_mgr_inbox0_cmd(struct dc_dmub_srv *dmub_srv, + union dmub_inbox0_cmd_lock_hw hw_lock_cmd) +{ + union dmub_inbox0_data_register data = { 0 }; + data.inbox0_cmd_lock_hw = hw_lock_cmd; + dc_dmub_srv_send_inbox0_cmd(dmub_srv, data); +} + bool should_use_dmub_lock(struct dc_link *link) { return false; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.h index bc5906347493..5a72b168fb4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.h @@ -34,6 +34,9 @@ void dmub_hw_lock_mgr_cmd(struct dc_dmub_srv *dmub_srv, union dmub_hw_lock_flags *hw_locks, struct dmub_hw_lock_inst_flags *inst_flags); +void dmub_hw_lock_mgr_inbox0_cmd(struct dc_dmub_srv *dmub_srv, + union dmub_inbox0_cmd_lock_hw hw_lock_cmd); + bool should_use_dmub_lock(struct dc_link *link); #endif /*_DMUB_HW_LOCK_MGR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c index 295596d1f47f..faad8555ddbb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c @@ -27,19 +27,10 @@ #include "dmub/inc/dmub_cmd.h" /** - ***************************************************************************** - * Function: dmub_enable_outbox_notification - * - * @brief - * Sends inbox cmd to dmub to enable outbox1 messages with interrupt. - * Dmub sends outbox1 message and triggers outbox1 interrupt. - * - * @param - * [in] dc: dc structure - * - * @return - * None - ***************************************************************************** + * dmub_enable_outbox_notification - Sends inbox cmd to dmub to enable outbox1 + * messages with interrupt. Dmub sends outbox1 + * message and triggers outbox1 interrupt. + * @dc: dc structure */ void dmub_enable_outbox_notification(struct dc *dc) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index 5e99553fcdd4..10d42ae0cffe 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -77,7 +77,7 @@ static enum dc_psr_state convert_psr_state(uint32_t raw_state) /* * Get PSR state from firmware. */ -static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state) +static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state, uint8_t panel_inst) { struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; uint32_t raw_state = 0; @@ -86,7 +86,7 @@ static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state) do { // Send gpint command and wait for ack - status = dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, 0, 30); + status = dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, panel_inst, 30); if (status == DMUB_STATUS_OK) { // GPINT was executed, get response @@ -105,7 +105,7 @@ static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state) /* * Set PSR version. */ -static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *stream) +static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *stream, uint8_t panel_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; @@ -125,6 +125,8 @@ static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state * cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_UNSUPPORTED; break; } + cmd.psr_set_version.psr_set_version_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; + cmd.psr_set_version.psr_set_version_data.panel_inst = panel_inst; cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data); dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); @@ -137,7 +139,7 @@ static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state * /* * Enable/Disable PSR. */ -static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait) +static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait, uint8_t panel_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; @@ -147,6 +149,9 @@ static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait) memset(&cmd, 0, sizeof(cmd)); cmd.psr_enable.header.type = DMUB_CMD__PSR; + cmd.psr_enable.data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; + cmd.psr_enable.data.panel_inst = panel_inst; + if (enable) cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_ENABLE; else @@ -164,7 +169,7 @@ static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait) */ if (wait) { for (retry_count = 0; retry_count <= 1000; retry_count++) { - dmub_psr_get_state(dmub, &state); + dmub_psr_get_state(dmub, &state, panel_inst); if (enable) { if (state != PSR_STATE0) @@ -186,13 +191,13 @@ static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait) /* * Set PSR level. */ -static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level) +static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_t panel_inst) { union dmub_rb_cmd cmd; enum dc_psr_state state = PSR_STATE0; struct dc_context *dc = dmub->ctx; - dmub_psr_get_state(dmub, &state); + dmub_psr_get_state(dmub, &state, panel_inst); if (state == PSR_STATE0) return; @@ -202,7 +207,8 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level) cmd.psr_set_level.header.sub_type = DMUB_CMD__PSR_SET_LEVEL; cmd.psr_set_level.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_level_data); cmd.psr_set_level.psr_set_level_data.psr_level = psr_level; - + cmd.psr_set_level.psr_set_level_data.cmd_version = PSR_VERSION_1; + cmd.psr_set_level.psr_set_level_data.panel_inst = panel_inst; dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); dc_dmub_srv_cmd_execute(dc->dmub_srv); dc_dmub_srv_wait_idle(dc->dmub_srv); @@ -213,7 +219,8 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level) */ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, struct dc_link *link, - struct psr_context *psr_context) + struct psr_context *psr_context, + uint8_t panel_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; @@ -237,7 +244,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, return false; // First, set the psr version - if (!dmub_psr_set_version(dmub, pipe_ctx->stream)) + if (!dmub_psr_set_version(dmub, pipe_ctx->stream, panel_inst)) return false; // Program DP DPHY fast training registers @@ -286,6 +293,8 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, copy_settings_data->debug.bitfields.use_hw_lock_mgr = 1; copy_settings_data->fec_enable_status = (link->fec_state == dc_link_fec_enabled); copy_settings_data->fec_enable_delay_in100us = link->dc->debug.fec_enable_delay_in100us; + copy_settings_data->cmd_version = PSR_VERSION_1; + copy_settings_data->panel_inst = panel_inst; dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); dc_dmub_srv_cmd_execute(dc->dmub_srv); @@ -297,12 +306,15 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, /* * Send command to PSR to force static ENTER and ignore all state changes until exit */ -static void dmub_psr_force_static(struct dmub_psr *dmub) +static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; memset(&cmd, 0, sizeof(cmd)); + + cmd.psr_force_static.psr_force_static_data.panel_inst = panel_inst; + cmd.psr_force_static.psr_force_static_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; cmd.psr_force_static.header.type = DMUB_CMD__PSR; cmd.psr_force_static.header.sub_type = DMUB_CMD__PSR_FORCE_STATIC; cmd.psr_enable.header.payload_bytes = 0; @@ -315,12 +327,13 @@ static void dmub_psr_force_static(struct dmub_psr *dmub) /* * Get PSR residency from firmware. */ -static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency) +static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency, uint8_t panel_inst) { struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; + uint16_t param = (uint16_t)(panel_inst << 8); - // Send gpint command and wait for ack - dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, 0, 30); + /* Send gpint command and wait for ack */ + dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, param, 30); dmub_srv_get_gpint_response(srv, residency); } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h index fe747c20a0d2..9675c269e649 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h @@ -35,12 +35,17 @@ struct dmub_psr { }; struct dmub_psr_funcs { - bool (*psr_copy_settings)(struct dmub_psr *dmub, struct dc_link *link, struct psr_context *psr_context); - void (*psr_enable)(struct dmub_psr *dmub, bool enable, bool wait); - void (*psr_get_state)(struct dmub_psr *dmub, enum dc_psr_state *dc_psr_state); - void (*psr_set_level)(struct dmub_psr *dmub, uint16_t psr_level); - void (*psr_force_static)(struct dmub_psr *dmub); - void (*psr_get_residency)(struct dmub_psr *dmub, uint32_t *residency); + bool (*psr_copy_settings)(struct dmub_psr *dmub, struct dc_link *link, + struct psr_context *psr_context, uint8_t panel_inst); + void (*psr_enable)(struct dmub_psr *dmub, bool enable, bool wait, + uint8_t panel_inst); + void (*psr_get_state)(struct dmub_psr *dmub, enum dc_psr_state *dc_psr_state, + uint8_t panel_inst); + void (*psr_set_level)(struct dmub_psr *dmub, uint16_t psr_level, + uint8_t panel_inst); + void (*psr_force_static)(struct dmub_psr *dmub, uint8_t panel_inst); + void (*psr_get_residency)(struct dmub_psr *dmub, uint32_t *residency, + uint8_t panel_inst); }; struct dmub_psr *dmub_psr_create(struct dc_context *ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 5ddeee96bf23..2938caaa2299 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -32,7 +32,6 @@ #include "core_status.h" #include "resource.h" #include "dm_helpers.h" -#include "dce110_hw_sequencer.h" #include "dce110_timing_generator.h" #include "dce/dce_hwseq.h" #include "gpio_service_interface.h" @@ -49,6 +48,9 @@ #include "link_encoder.h" #include "link_hwss.h" #include "dc_link_dp.h" +#if defined(CONFIG_DRM_AMD_DC_DCN) +#include "dccg.h" +#endif #include "clock_source.h" #include "clk_mgr.h" #include "abm.h" @@ -63,6 +65,8 @@ #include "atomfirmware.h" +#include "dcn10/dcn10_hw_sequencer.h" + #define GAMMA_HW_POINTS_NUM 256 /* @@ -264,6 +268,7 @@ static void build_prescale_params(struct ipp_prescale_params *prescale_params, prescale_params->scale = 0x2008; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: prescale_params->scale = 0x2000; break; @@ -1306,41 +1311,6 @@ static void build_audio_output( pipe_ctx->pll_settings.ss_percentage; } -static void get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx, - struct tg_color *color) -{ - uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4; - - switch (pipe_ctx->plane_res.scl_data.format) { - case PIXEL_FORMAT_ARGB8888: - /* set boarder color to red */ - color->color_r_cr = color_value; - break; - - case PIXEL_FORMAT_ARGB2101010: - /* set boarder color to blue */ - color->color_b_cb = color_value; - break; - case PIXEL_FORMAT_420BPP8: - /* set boarder color to green */ - color->color_g_y = color_value; - break; - case PIXEL_FORMAT_420BPP10: - /* set boarder color to yellow */ - color->color_g_y = color_value; - color->color_r_cr = color_value; - break; - case PIXEL_FORMAT_FP16: - /* set boarder color to white */ - color->color_r_cr = color_value; - color->color_b_cb = color_value; - color->color_g_y = color_value; - break; - default: - break; - } -} - static void program_scaler(const struct dc *dc, const struct pipe_ctx *pipe_ctx) { @@ -2120,11 +2090,31 @@ static void dce110_setup_audio_dto( build_audio_output(context, pipe_ctx, &audio_output); +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* For DCN3.1, audio to HPO FRL encoder is using audio DTBCLK DTO */ + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) { + /* disable audio DTBCLK DTO */ + dc->res_pool->dccg->funcs->set_audio_dtbclk_dto( + dc->res_pool->dccg, 0); + + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + } else + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); +#else pipe_ctx->stream_res.audio->funcs->wall_dto_setup( pipe_ctx->stream_res.audio, pipe_ctx->stream->signal, &audio_output.crtc_info, &audio_output.pll_info); +#endif break; } } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index 8bbb499067f7..db7557a1c613 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -393,6 +393,7 @@ static void program_pixel_format( grph_format = 1; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: grph_depth = 3; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index d88a74559edd..27cbb5b42c7e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -2231,6 +2231,7 @@ static const struct timing_generator_funcs dce110_tg_funcs = { dce110_timing_generator_enable_advanced_request, .set_drr = dce110_timing_generator_set_drr, + .get_last_used_drr_vtotal = NULL, .set_static_screen_control = dce110_timing_generator_set_static_screen_control, .set_test_pattern = dce110_timing_generator_set_test_pattern, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c index 29438c6050db..45bca0db5e5e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c @@ -708,7 +708,8 @@ bool dce110_transform_v_construct( xfm_dce->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; xfm_dce->prescaler_on = true; xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c index b57c466124e7..4af0c70098c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c @@ -1190,6 +1190,7 @@ static const struct timing_generator_funcs dce120_tg_funcs = { .tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock, .enable_advanced_request = dce120_timing_generator_enable_advanced_request, .set_drr = dce120_timing_generator_set_drr, + .get_last_used_drr_vtotal = NULL, .set_static_screen_control = dce120_timing_generator_set_static_screen_control, .set_test_pattern = dce120_timing_generator_set_test_pattern, .arm_vert_intr = dce120_arm_vert_intr, diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c index 397e7f94e1e8..b8fd43dc010b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c @@ -209,6 +209,7 @@ static const struct timing_generator_funcs dce80_tg_funcs = { .tear_down_global_swap_lock = dce110_timing_generator_tear_down_global_swap_lock, .set_drr = dce110_timing_generator_set_drr, + .get_last_used_drr_vtotal = NULL, .set_static_screen_control = dce110_timing_generator_set_static_screen_control, .set_test_pattern = dce110_timing_generator_set_test_pattern, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index 7f8456b9988b..91fdfcd8a14e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -257,7 +257,8 @@ static void dpp1_setup_format_flags(enum surface_pixel_format input_format,\ if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F || input_format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) *fmt = PIXEL_FORMAT_FLOAT; - else if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616) + else if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 || + input_format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616) *fmt = PIXEL_FORMAT_FIXED16; else *fmt = PIXEL_FORMAT_FIXED; @@ -368,7 +369,8 @@ void dpp1_cnv_setup ( select = INPUT_CSC_SELECT_ICSC; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: - pixel_format = 22; + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: + pixel_format = 26; /* ARGB16161616_UNORM */ break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: pixel_format = 24; @@ -566,7 +568,8 @@ void dpp1_construct( dpp->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 9a1f40eb5c47..71b3a6949001 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1497,8 +1497,6 @@ void dpp1_cnv_setup ( enum dc_color_space input_color_space, struct cnv_alpha_2bit_lut *alpha_2bit_lut); -void dpp1_full_bypass(struct dpp *dpp_base); - void dpp1_dppclk_control( struct dpp *dpp_base, bool dppclk_div, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index 0bd8de4c73a9..673b93f4fea5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -631,8 +631,10 @@ static void dpp1_dscl_set_manual_ratio_init( SCL_V_INIT_INT, init_int); if (REG(SCL_VERT_FILTER_INIT_BOT)) { - init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5; - init_int = dc_fixpt_floor(data->inits.v_bot); + struct fixed31_32 bot = dc_fixpt_add(data->inits.v, data->ratios.vert); + + init_frac = dc_fixpt_u0d19(bot) << 5; + init_int = dc_fixpt_floor(bot); REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, SCL_V_INIT_FRAC_BOT, init_frac, SCL_V_INIT_INT_BOT, init_int); @@ -645,8 +647,10 @@ static void dpp1_dscl_set_manual_ratio_init( SCL_V_INIT_INT_C, init_int); if (REG(SCL_VERT_FILTER_INIT_BOT_C)) { - init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5; - init_int = dc_fixpt_floor(data->inits.v_c_bot); + struct fixed31_32 bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); + + init_frac = dc_fixpt_u0d19(bot) << 5; + init_int = dc_fixpt_floor(bot); REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, SCL_V_INIT_FRAC_BOT_C, init_frac, SCL_V_INIT_INT_BOT_C, init_int); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 6f42d10dd772..f4f423d0b8c3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -785,6 +785,7 @@ static bool hubbub1_dcc_support_pixel_format( *bytes_per_element = 4; return true; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: *bytes_per_element = 8; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 343a537172c7..8d7e92d5d3e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -139,6 +139,21 @@ struct dcn_hubbub_registers { uint32_t DCHVM_CLK_CTRL; uint32_t DCHVM_RIOMMU_CTRL0; uint32_t DCHVM_RIOMMU_STAT0; + uint32_t DCHUBBUB_DET0_CTRL; + uint32_t DCHUBBUB_DET1_CTRL; + uint32_t DCHUBBUB_DET2_CTRL; + uint32_t DCHUBBUB_DET3_CTRL; + uint32_t DCHUBBUB_COMPBUF_CTRL; + uint32_t COMPBUF_RESERVED_SPACE; + uint32_t DCHUBBUB_DEBUG_CTRL_0; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D; }; /* set field name */ @@ -276,16 +291,42 @@ struct dcn_hubbub_registers { type RIOMMU_ACTIVE; \ type HOSTVM_PREFETCH_DONE +#define HUBBUB_RET_REG_FIELD_LIST(type) \ + type DET_DEPTH;\ + type DET0_SIZE;\ + type DET1_SIZE;\ + type DET2_SIZE;\ + type DET3_SIZE;\ + type DET0_SIZE_CURRENT;\ + type DET1_SIZE_CURRENT;\ + type DET2_SIZE_CURRENT;\ + type DET3_SIZE_CURRENT;\ + type COMPBUF_SIZE;\ + type COMPBUF_SIZE_CURRENT;\ + type COMPBUF_RESERVED_SPACE_64B;\ + type COMPBUF_RESERVED_SPACE_ZS;\ + type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A;\ + type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A;\ + type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B;\ + type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B;\ + type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C;\ + type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C;\ + type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D;\ + type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D + + struct dcn_hubbub_shift { DCN_HUBBUB_REG_FIELD_LIST(uint8_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint8_t); HUBBUB_HVM_REG_FIELD_LIST(uint8_t); + HUBBUB_RET_REG_FIELD_LIST(uint8_t); }; struct dcn_hubbub_mask { DCN_HUBBUB_REG_FIELD_LIST(uint32_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint32_t); HUBBUB_HVM_REG_FIELD_LIST(uint32_t); + HUBBUB_RET_REG_FIELD_LIST(uint32_t); }; struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index e39e8a2f715d..04303fe9c659 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -245,6 +245,7 @@ void hubp1_program_pixel_format( if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { red_bar = 2; blue_bar = 3; @@ -277,8 +278,9 @@ void hubp1_program_pixel_format( SURFACE_PIXEL_FORMAT, 10); break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: /*we use crossbar already*/ REG_UPDATE(DCSURF_SURFACE_CONFIG, - SURFACE_PIXEL_FORMAT, 22); + SURFACE_PIXEL_FORMAT, 26); /* ARGB16161616_UNORM */ break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 81803463ca9b..c545eddabdcc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -54,6 +54,8 @@ #include "dce/dmub_hw_lock_mgr.h" #include "dc_trace.h" #include "dce/dmub_outbox.h" +#include "inc/dc_link_dp.h" +#include "inc/link_dpcd.h" #define DC_LOGGER_INIT(logger) @@ -1403,6 +1405,9 @@ void dcn10_init_hw(struct dc *dc) if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) continue; + /* DP 2.0 requires that LTTPR Caps be read first */ + dp_retrieve_lttpr_cap(dc->links[i]); + /* * If any of the displays are lit up turn them off. * The reason is that some MST hubs cannot be turned off @@ -2407,83 +2412,6 @@ void dcn10_program_output_csc(struct dc *dc, } } -void dcn10_get_surface_visual_confirm_color( - const struct pipe_ctx *pipe_ctx, - struct tg_color *color) -{ - uint32_t color_value = MAX_TG_COLOR_VALUE; - - switch (pipe_ctx->plane_res.scl_data.format) { - case PIXEL_FORMAT_ARGB8888: - /* set border color to red */ - color->color_r_cr = color_value; - break; - - case PIXEL_FORMAT_ARGB2101010: - /* set border color to blue */ - color->color_b_cb = color_value; - break; - case PIXEL_FORMAT_420BPP8: - /* set border color to green */ - color->color_g_y = color_value; - break; - case PIXEL_FORMAT_420BPP10: - /* set border color to yellow */ - color->color_g_y = color_value; - color->color_r_cr = color_value; - break; - case PIXEL_FORMAT_FP16: - /* set border color to white */ - color->color_r_cr = color_value; - color->color_b_cb = color_value; - color->color_g_y = color_value; - break; - default: - break; - } -} - -void dcn10_get_hdr_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color) -{ - uint32_t color_value = MAX_TG_COLOR_VALUE; - - // Determine the overscan color based on the top-most (desktop) plane's context - struct pipe_ctx *top_pipe_ctx = pipe_ctx; - - while (top_pipe_ctx->top_pipe != NULL) - top_pipe_ctx = top_pipe_ctx->top_pipe; - - switch (top_pipe_ctx->plane_res.scl_data.format) { - case PIXEL_FORMAT_ARGB2101010: - if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { - /* HDR10, ARGB2101010 - set border color to red */ - color->color_r_cr = color_value; - } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { - /* FreeSync 2 ARGB2101010 - set border color to pink */ - color->color_r_cr = color_value; - color->color_b_cb = color_value; - } - break; - case PIXEL_FORMAT_FP16: - if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { - /* HDR10, FP16 - set border color to blue */ - color->color_b_cb = color_value; - } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { - /* FreeSync 2 HDR - set border color to green */ - color->color_g_y = color_value; - } - break; - default: - /* SDR - set border color to Gray */ - color->color_r_cr = color_value/2; - color->color_b_cb = color_value/2; - color->color_g_y = color_value/2; - break; - } -} - static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) { struct dc_bias_and_scale bns_params = {0}; @@ -2504,13 +2432,14 @@ static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state void dcn10_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, int mpcc_id) { - struct dce_hwseq *hws = dc->hwseq; struct mpc *mpc = dc->res_pool->mpc; if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) - hws->funcs.get_hdr_visual_confirm_color(pipe_ctx, color); + get_hdr_visual_confirm_color(pipe_ctx, color); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) - hws->funcs.get_surface_visual_confirm_color(pipe_ctx, color); + get_surface_visual_confirm_color(pipe_ctx, color); + else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE) + get_surface_tile_visual_confirm_color(pipe_ctx, color); else color_space_to_black_color( dc, pipe_ctx->stream->output_color_space, color); @@ -2560,11 +2489,10 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) */ mpcc_id = hubp->inst; - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); - /* If there is no full update, don't need to touch MPC tree*/ if (!pipe_ctx->plane_state->update_flags.bits.full_update) { mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); return; } @@ -2586,6 +2514,7 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) NULL, hubp->inst, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); ASSERT(new_mpcc != NULL); @@ -2599,7 +2528,7 @@ static void update_scaler(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; - pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; /* scaler configuration */ pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); @@ -3316,10 +3245,17 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) * about the actual size being incorrect, that's a limitation of * the hardware. */ - x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / - pipe_ctx->plane_state->dst_rect.width; - y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / - pipe_ctx->plane_state->dst_rect.height; + if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) { + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.height; + } else { + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.height; + } /** * If the cursor's source viewport is clipped then we need to diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 478180b96d8d..9ae07c77fdc0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -189,12 +189,6 @@ void dcn10_bios_golden_init(struct dc *dc); void dcn10_plane_atomic_power_down(struct dc *dc, struct dpp *dpp, struct hubp *hubp); -void dcn10_get_surface_visual_confirm_color( - const struct pipe_ctx *pipe_ctx, - struct tg_color *color); -void dcn10_get_hdr_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color); bool dcn10_disconnect_pipes( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index 4ff3ebc25438..34001a30d449 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -112,8 +112,6 @@ static const struct hwseq_private_funcs dcn10_private_funcs = { .dpp_pg_control = dcn10_dpp_pg_control, .hubp_pg_control = dcn10_hubp_pg_control, .dsc_pg_control = NULL, - .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, - .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 3e1a582e4b88..d8b22618b79e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -160,6 +160,12 @@ struct dcn10_link_enc_registers { uint32_t PHYA_LINK_CNTL2; uint32_t PHYB_LINK_CNTL2; uint32_t PHYC_LINK_CNTL2; + uint32_t DIO_LINKA_CNTL; + uint32_t DIO_LINKB_CNTL; + uint32_t DIO_LINKC_CNTL; + uint32_t DIO_LINKD_CNTL; + uint32_t DIO_LINKE_CNTL; + uint32_t DIO_LINKF_CNTL; }; #define LE_SF(reg_name, field_name, post_fix)\ @@ -460,16 +466,23 @@ struct dcn10_link_enc_registers { type DPCS_TX_DATA_ORDER_INVERT_18_BIT;\ type RDPCS_TX_CLK_EN +#define DCN31_LINK_ENCODER_REG_FIELD_LIST(type) \ + type ENC_TYPE_SEL;\ + type HPO_DP_ENC_SEL;\ + type HPO_HDMI_ENC_SEL + struct dcn10_link_enc_shift { DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN20_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN30_LINK_ENCODER_REG_FIELD_LIST(uint8_t); + DCN31_LINK_ENCODER_REG_FIELD_LIST(uint8_t); }; struct dcn10_link_enc_mask { DCN_LINK_ENCODER_REG_FIELD_LIST(uint32_t); DCN20_LINK_ENCODER_REG_FIELD_LIST(uint32_t); DCN30_LINK_ENCODER_REG_FIELD_LIST(uint32_t); + DCN31_LINK_ENCODER_REG_FIELD_LIST(uint32_t); }; struct dcn10_link_encoder { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c index da74269feb75..11019c2c62cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -45,6 +45,8 @@ void mpc1_set_bg_color(struct mpc *mpc, struct mpcc *bottommost_mpcc = mpc1_get_mpcc(mpc, mpcc_id); uint32_t bg_r_cr, bg_g_y, bg_b_cb; + bottommost_mpcc->blnd_cfg.black_color = *bg_color; + /* find bottommost mpcc. */ while (bottommost_mpcc->mpcc_bot) { bottommost_mpcc = bottommost_mpcc->mpcc_bot; @@ -64,8 +66,6 @@ void mpc1_set_bg_color(struct mpc *mpc, MPCC_BG_G_Y, bg_g_y); REG_SET(MPCC_BG_B_CB[bottommost_mpcc->mpcc_id], 0, MPCC_BG_B_CB, bg_b_cb); - - bottommost_mpcc->blnd_cfg.black_color = *bg_color; } static void mpc1_update_blending( @@ -83,7 +83,6 @@ static void mpc1_update_blending( MPCC_GLOBAL_ALPHA, blnd_cfg->global_alpha, MPCC_GLOBAL_GAIN, blnd_cfg->global_gain); - mpc1_set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id); mpcc->blnd_cfg = *blnd_cfg; } @@ -248,8 +247,6 @@ struct mpcc *mpc1_insert_plane( } } - mpc->funcs->set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id); - /* update the blending configuration */ mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 677663cc7bff..3696faf12d86 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -968,6 +968,17 @@ void optc1_set_drr( } } +void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_V_TOTAL_MAX, 0, + OTG_V_TOTAL_MAX, vtotal_max); + + REG_SET(OTG_V_TOTAL_MIN, 0, + OTG_V_TOTAL_MIN, vtotal_min); +} + static void optc1_set_test_pattern( struct timing_generator *optc, /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' @@ -1543,6 +1554,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .unlock = optc1_unlock, .enable_optc_clock = optc1_enable_optc_clock, .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = NULL, .set_static_screen_control = optc1_set_static_screen_control, .set_test_pattern = optc1_set_test_pattern, .program_stereo = optc1_program_stereo, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index cabfe83fd634..29d6fbe0093a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -171,6 +171,7 @@ struct dcn_optc_registers { uint32_t OPTC_DATA_FORMAT_CONTROL; uint32_t OPTC_BYTES_PER_PIXEL; uint32_t OPTC_WIDTH_CONTROL; + uint32_t OTG_DRR_CONTROL; uint32_t OTG_BLANK_DATA_COLOR; uint32_t OTG_BLANK_DATA_COLOR_EXT; uint32_t OTG_DRR_TRIGGER_WINDOW; @@ -517,7 +518,8 @@ struct dcn_optc_registers { type OTG_CRC_DSC_MODE;\ type OTG_CRC_DATA_STREAM_COMBINE_MODE;\ type OTG_CRC_DATA_STREAM_SPLIT_MODE;\ - type OTG_CRC_DATA_FORMAT; + type OTG_CRC_DATA_FORMAT;\ + type OTG_V_TOTAL_LAST_USED_BY_DRR; struct dcn_optc_shift { @@ -666,6 +668,8 @@ void optc1_set_drr( struct timing_generator *optc, const struct drr_params *params); +void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max); + void optc1_set_static_screen_control( struct timing_generator *optc, uint32_t event_triggers, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index f962b905e79e..7daadb6a5233 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1266,8 +1266,6 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont static enum dc_status dcn10_patch_unknown_plane_state(struct dc_plane_state *plane_state) { - enum dc_status result = DC_OK; - enum surface_pixel_format surf_pix_format = plane_state->format; unsigned int bpp = resource_pixel_format_to_bpp(surf_pix_format); @@ -1279,7 +1277,7 @@ static enum dc_status dcn10_patch_unknown_plane_state(struct dc_plane_state *pla swizzle = DC_SW_64KB_S; plane_state->tiling_info.gfx9.swizzle = swizzle; - return result; + return DC_OK; } struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index 76b334644f9e..0d86df97878c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -52,6 +52,7 @@ SRI(AFMT_60958_1, DIG, id), \ SRI(AFMT_60958_2, DIG, id), \ SRI(DIG_FE_CNTL, DIG, id), \ + SRI(DIG_FIFO_STATUS, DIG, id), \ SRI(HDMI_CONTROL, DIG, id), \ SRI(HDMI_DB_CONTROL, DIG, id), \ SRI(HDMI_GC, DIG, id), \ @@ -124,6 +125,7 @@ struct dcn10_stream_enc_registers { uint32_t AFMT_60958_2; uint32_t DIG_FE_CNTL; uint32_t DIG_FE_CNTL2; + uint32_t DIG_FIFO_STATUS; uint32_t DP_MSE_RATE_CNTL; uint32_t DP_MSE_RATE_UPDATE; uint32_t DP_PIXEL_FORMAT; @@ -266,6 +268,17 @@ struct dcn10_stream_enc_registers { SE_SF(DIG0_DIG_FE_CNTL, TMDS_COLOR_FORMAT, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_LEVEL_ERROR, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_USE_OVERWRITE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_OVERWRITE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_ERROR_ACK, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_CAL_AVERAGE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_MAXIMUM_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_MINIMUM_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_READ_CLOCK_SRC, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_CALIBRATED, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_FORCE_RECAL_AVERAGE, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_FORCE_RECOMP_MINMAX, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_LOCK_STATUS, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT_CLR, mask_sh),\ @@ -488,6 +501,17 @@ struct dcn10_stream_enc_registers { type DP_VID_N_MUL;\ type DP_VID_M_DOUBLE_VALUE_EN;\ type DIG_SOURCE_SELECT;\ + type DIG_FIFO_LEVEL_ERROR;\ + type DIG_FIFO_USE_OVERWRITE_LEVEL;\ + type DIG_FIFO_OVERWRITE_LEVEL;\ + type DIG_FIFO_ERROR_ACK;\ + type DIG_FIFO_CAL_AVERAGE_LEVEL;\ + type DIG_FIFO_MAXIMUM_LEVEL;\ + type DIG_FIFO_MINIMUM_LEVEL;\ + type DIG_FIFO_READ_CLOCK_SRC;\ + type DIG_FIFO_CALIBRATED;\ + type DIG_FIFO_FORCE_RECAL_AVERAGE;\ + type DIG_FIFO_FORCE_RECOMP_MINMAX;\ type DIG_CLOCK_PATTERN #define SE_REG_FIELD_LIST_DCN2_0(type) \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c index 8774406120fc..5999b2da3a01 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c @@ -96,6 +96,39 @@ void dccg2_get_dccg_ref_freq(struct dccg *dccg, return; } +void dccg2_set_fifo_errdet_ovr_en(struct dccg *dccg, + bool en) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, + DCCG_FIFO_ERRDET_OVR_EN, en ? 1 : 0); +} + +void dccg2_otg_add_pixel(struct dccg *dccg, + uint32_t otg_inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[otg_inst], + OTG_ADD_PIXEL[otg_inst], 0, + OTG_DROP_PIXEL[otg_inst], 0); + REG_UPDATE(OTG_PIXEL_RATE_CNTL[otg_inst], + OTG_ADD_PIXEL[otg_inst], 1); +} + +void dccg2_otg_drop_pixel(struct dccg *dccg, + uint32_t otg_inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[otg_inst], + OTG_ADD_PIXEL[otg_inst], 0, + OTG_DROP_PIXEL[otg_inst], 0); + REG_UPDATE(OTG_PIXEL_RATE_CNTL[otg_inst], + OTG_DROP_PIXEL[otg_inst], 1); +} + void dccg2_init(struct dccg *dccg) { } @@ -103,6 +136,9 @@ void dccg2_init(struct dccg *dccg) static const struct dccg_funcs dccg2_funcs = { .update_dpp_dto = dccg2_update_dpp_dto, .get_dccg_ref_freq = dccg2_get_dccg_ref_freq, + .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, + .otg_add_pixel = dccg2_otg_add_pixel, + .otg_drop_pixel = dccg2_otg_drop_pixel, .dccg_init = dccg2_init }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index d407f33308b9..ede65100a050 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -34,12 +34,19 @@ DCCG_SRII(DTO_PARAM, DPPCLK, 1),\ DCCG_SRII(DTO_PARAM, DPPCLK, 2),\ DCCG_SRII(DTO_PARAM, DPPCLK, 3),\ - SR(REFCLK_CNTL) + SR(REFCLK_CNTL),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SR(DISPCLK_FREQ_CHANGE_CNTL) #define DCCG_REG_LIST_DCN2() \ DCCG_COMMON_REG_LIST_DCN_BASE(),\ DCCG_SRII(DTO_PARAM, DPPCLK, 4),\ - DCCG_SRII(DTO_PARAM, DPPCLK, 5) + DCCG_SRII(DTO_PARAM, DPPCLK, 5),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 4),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 5) #define DCCG_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -47,6 +54,9 @@ #define DCCG_SFI(reg_name, field_name, field_prefix, inst, post_fix)\ .field_prefix ## _ ## field_name[inst] = reg_name ## __ ## field_prefix ## inst ## _ ## field_name ## post_fix +#define DCCG_SFII(block, reg_name, field_prefix, field_name, inst, post_fix)\ + .field_prefix ## _ ## field_name[inst] = block ## inst ## _ ## reg_name ## __ ## field_prefix ## inst ## _ ## field_name ## post_fix + #define DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\ @@ -59,14 +69,49 @@ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(REFCLK_CNTL, REFCLK_CLOCK_EN, mask_sh),\ - DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh) + DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_STEP_DELAY, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_STEP_SIZE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_MAX_ERRDET_CYCLES, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_RESET, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_STATE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_OVR_EN, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_CHG_FWD_CORR_DISABLE, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 1, mask_sh) + + + #define DCCG_MASK_SH_LIST_DCN2(mask_sh) \ DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 4, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 4, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 5, mask_sh),\ - DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 5, mask_sh) + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 5, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 4, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 5, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 4, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 5, mask_sh) + +#define DCCG_MASK_SH_LIST_DCN2_1(mask_sh) \ + DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 4, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 4, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 5, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 5, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 3, mask_sh) + #define DCCG_REG_FIELD_LIST(type) \ type DPPCLK0_DTO_PHASE;\ @@ -74,7 +119,18 @@ type DPPCLK_DTO_ENABLE[6];\ type DPPCLK_DTO_DB_EN[6];\ type REFCLK_CLOCK_EN;\ - type REFCLK_SRC_SEL; + type REFCLK_SRC_SEL;\ + type DISPCLK_STEP_DELAY;\ + type DISPCLK_STEP_SIZE;\ + type DISPCLK_FREQ_RAMP_DONE;\ + type DISPCLK_MAX_ERRDET_CYCLES;\ + type DCCG_FIFO_ERRDET_RESET;\ + type DCCG_FIFO_ERRDET_STATE;\ + type DCCG_FIFO_ERRDET_OVR_EN;\ + type DISPCLK_CHG_FWD_CORR_DISABLE;\ + type DISPCLK_FREQ_CHANGE_CNTL;\ + type OTG_ADD_PIXEL[MAX_PIPES];\ + type OTG_DROP_PIXEL[MAX_PIPES]; #define DCCG3_REG_FIELD_LIST(type) \ type PHYASYMCLK_FORCE_EN;\ @@ -84,24 +140,71 @@ type PHYCSYMCLK_FORCE_EN;\ type PHYCSYMCLK_FORCE_SRC_SEL; +#define DCCG31_REG_FIELD_LIST(type) \ + type PHYDSYMCLK_FORCE_EN;\ + type PHYDSYMCLK_FORCE_SRC_SEL;\ + type PHYESYMCLK_FORCE_EN;\ + type PHYESYMCLK_FORCE_SRC_SEL;\ + type DPSTREAMCLK_PIPE0_EN;\ + type DPSTREAMCLK_PIPE1_EN;\ + type DPSTREAMCLK_PIPE2_EN;\ + type DPSTREAMCLK_PIPE3_EN;\ + type HDMISTREAMCLK0_SRC_SEL;\ + type HDMISTREAMCLK0_DTO_FORCE_DIS;\ + type SYMCLK32_SE0_SRC_SEL;\ + type SYMCLK32_SE1_SRC_SEL;\ + type SYMCLK32_SE2_SRC_SEL;\ + type SYMCLK32_SE3_SRC_SEL;\ + type SYMCLK32_SE0_EN;\ + type SYMCLK32_SE1_EN;\ + type SYMCLK32_SE2_EN;\ + type SYMCLK32_SE3_EN;\ + type SYMCLK32_LE0_SRC_SEL;\ + type SYMCLK32_LE1_SRC_SEL;\ + type SYMCLK32_LE0_EN;\ + type SYMCLK32_LE1_EN;\ + type DTBCLK_DTO_ENABLE[MAX_PIPES];\ + type DTBCLKDTO_ENABLE_STATUS[MAX_PIPES];\ + type PIPE_DTO_SRC_SEL[MAX_PIPES];\ + type DTBCLK_DTO_DIV[MAX_PIPES];\ + type DCCG_AUDIO_DTO_SEL;\ + type DCCG_AUDIO_DTO0_SOURCE_SEL;\ + type DENTIST_DISPCLK_CHG_MODE; + struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) DCCG3_REG_FIELD_LIST(uint8_t) + DCCG31_REG_FIELD_LIST(uint8_t) }; struct dccg_mask { DCCG_REG_FIELD_LIST(uint32_t) DCCG3_REG_FIELD_LIST(uint32_t) + DCCG31_REG_FIELD_LIST(uint32_t) }; struct dccg_registers { uint32_t DPPCLK_DTO_CTRL; uint32_t DPPCLK_DTO_PARAM[6]; uint32_t REFCLK_CNTL; + uint32_t DISPCLK_FREQ_CHANGE_CNTL; + uint32_t OTG_PIXEL_RATE_CNTL[MAX_PIPES]; uint32_t HDMICHARCLK_CLOCK_CNTL[6]; uint32_t PHYASYMCLK_CLOCK_CNTL; uint32_t PHYBSYMCLK_CLOCK_CNTL; uint32_t PHYCSYMCLK_CLOCK_CNTL; + uint32_t PHYDSYMCLK_CLOCK_CNTL; + uint32_t PHYESYMCLK_CLOCK_CNTL; + uint32_t DTBCLK_DTO_MODULO[MAX_PIPES]; + uint32_t DTBCLK_DTO_PHASE[MAX_PIPES]; + uint32_t DCCG_AUDIO_DTBCLK_DTO_MODULO; + uint32_t DCCG_AUDIO_DTBCLK_DTO_PHASE; + uint32_t DCCG_AUDIO_DTO_SOURCE; + uint32_t DPSTREAMCLK_CNTL; + uint32_t HDMISTREAMCLK_CNTL; + uint32_t SYMCLK32_SE_CNTL; + uint32_t SYMCLK32_LE_CNTL; + uint32_t DENTIST_DISPCLK_CNTL; }; struct dcn_dccg { @@ -117,6 +220,14 @@ void dccg2_get_dccg_ref_freq(struct dccg *dccg, unsigned int xtalin_freq_inKhz, unsigned int *dccg_ref_freq_inKhz); +void dccg2_set_fifo_errdet_ovr_en(struct dccg *dccg, + bool en); +void dccg2_otg_add_pixel(struct dccg *dccg, + uint32_t otg_inst); +void dccg2_otg_drop_pixel(struct dccg *dccg, + uint32_t otg_inst); + + void dccg2_init(struct dccg *dccg); struct dccg *dccg2_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c index 4af96cc5d9d6..a9e420c7d75a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c @@ -166,7 +166,8 @@ static void dpp2_cnv_setup ( select = DCN2_ICSC_SELECT_ICSC_A; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: - pixel_format = 22; + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: + pixel_format = 26; /* ARGB16161616_UNORM */ break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: pixel_format = 24; @@ -431,7 +432,8 @@ bool dpp2_construct( dpp->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c index 6d03d98fca22..91a9305d42e8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c @@ -158,6 +158,7 @@ bool hubbub2_dcc_support_pixel_format( *bytes_per_element = 4; return true; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: *bytes_per_element = 8; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h index c478213ba7ad..10af257d90ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h @@ -83,6 +83,13 @@ struct dcn20_hubbub { int num_vmid; struct dcn20_vmid vmid[16]; unsigned int detile_buf_size; + unsigned int crb_size_segs; + unsigned int compbuf_size_segments; + unsigned int pixel_chunk_size; + unsigned int det0_size; + unsigned int det1_size; + unsigned int det2_size; + unsigned int det3_size; }; void hubbub2_construct(struct dcn20_hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index a1318c31bcfa..7e54058715aa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -431,6 +431,7 @@ void hubp2_program_pixel_format( if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { red_bar = 2; blue_bar = 3; @@ -463,8 +464,9 @@ void hubp2_program_pixel_format( SURFACE_PIXEL_FORMAT, 10); break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: /*we use crossbar already*/ REG_UPDATE(DCSURF_SURFACE_CONFIG, - SURFACE_PIXEL_FORMAT, 22); + SURFACE_PIXEL_FORMAT, 26); /* ARGB16161616_UNORM */ break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h index f501c02c244b..eea2254b15e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h @@ -216,16 +216,22 @@ type ROW_TTU_MODE; \ type NUM_PKRS +#define DCN31_HUBP_REG_FIELD_VARIABLE_LIST(type) \ + DCN30_HUBP_REG_FIELD_VARIABLE_LIST(type);\ + type HUBP_UNBOUNDED_REQ_MODE;\ + type CURSOR_REQ_MODE;\ + type HUBP_SOFT_RESET + struct dcn_hubp2_registers { DCN30_HUBP_REG_COMMON_VARIABLE_LIST; }; struct dcn_hubp2_shift { - DCN30_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); + DCN31_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); }; struct dcn_hubp2_mask { - DCN30_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); + DCN31_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); }; struct dcn20_hubp { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 25de15158801..5c2853654cca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -51,6 +51,7 @@ #include "dccg.h" #include "dc_dmub_srv.h" #include "dce/dmub_hw_lock_mgr.h" +#include "hw_sequencer.h" #define DC_LOGGER_INIT(logger) @@ -243,7 +244,7 @@ void dcn20_dccg_init(struct dce_hwseq *hws) REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); /* This value is dependent on the hardware pipeline delay so set once per SOC */ - REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); + REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c); } void dcn20_disable_vga( @@ -1269,6 +1270,7 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx new_pipe->update_flags.bits.gamut_remap = 1; new_pipe->update_flags.bits.scaler = 1; new_pipe->update_flags.bits.viewport = 1; + new_pipe->update_flags.bits.det_size = 1; if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { new_pipe->update_flags.bits.odm = 1; new_pipe->update_flags.bits.global_sync = 1; @@ -1303,6 +1305,9 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx new_pipe->update_flags.bits.global_sync = 1; } + if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb) + new_pipe->update_flags.bits.det_size = 1; + /* * Detect opp / tg change, only set on change, not on enable * Assume mpcc inst = pipe index, if not this code needs to be updated @@ -1418,6 +1423,9 @@ static void dcn20_update_dchubp_dpp( &pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param); + + if (hubp->funcs->set_unbounded_requesting) + hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req); } if (pipe_ctx->update_flags.bits.hubp_interdependent) hubp->funcs->hubp_setup_interdependent( @@ -1473,7 +1481,7 @@ static void dcn20_update_dchubp_dpp( plane_state->update_flags.bits.per_pixel_alpha_change || pipe_ctx->stream->update_flags.bits.scaling) { pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; - ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP); + ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); /* scaler configuration */ pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); @@ -1597,6 +1605,10 @@ static void dcn20_program_pipe( dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub); } + if (dc->res_pool->hubbub->funcs->program_det_size && pipe_ctx->update_flags.bits.det_size) + dc->res_pool->hubbub->funcs->program_det_size( + dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); + if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) dcn20_update_dchubp_dpp(dc, pipe_ctx, context); @@ -1687,6 +1699,10 @@ void dcn20_program_front_end_for_ctx( for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { + struct hubbub *hubbub = dc->res_pool->hubbub; + + if (hubbub->funcs->program_det_size && context->res_ctx.pipe_ctx[i].update_flags.bits.disable) + hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); } @@ -1804,6 +1820,9 @@ void dcn20_prepare_bandwidth( &context->bw_ctx.bw.dcn.watermarks, dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, false); + /* decrease compbuf size */ + if (hubbub->funcs->program_compbuf_size) + hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, false); } void dcn20_optimize_bandwidth( @@ -1822,6 +1841,9 @@ void dcn20_optimize_bandwidth( dc->clk_mgr, context, true); + /* increase compbuf size */ + if (hubbub->funcs->program_compbuf_size) + hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true); } bool dcn20_update_bandwidth( @@ -2245,40 +2267,19 @@ void dcn20_reset_hw_ctx_wrap( } } -void dcn20_get_mpctree_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color) -{ - const struct tg_color pipe_colors[6] = { - {MAX_TG_COLOR_VALUE, 0, 0}, // red - {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE / 4, 0}, // orange - {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE, 0}, // yellow - {0, MAX_TG_COLOR_VALUE, 0}, // green - {0, 0, MAX_TG_COLOR_VALUE}, // blue - {MAX_TG_COLOR_VALUE / 2, 0, MAX_TG_COLOR_VALUE / 2}, // purple - }; - - struct pipe_ctx *top_pipe = pipe_ctx; - - while (top_pipe->top_pipe) { - top_pipe = top_pipe->top_pipe; - } - - *color = pipe_colors[top_pipe->pipe_idx]; -} - void dcn20_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, int mpcc_id) { - struct dce_hwseq *hws = dc->hwseq; struct mpc *mpc = dc->res_pool->mpc; - /* input to MPCC is always RGB, by default leave black_color at 0 */ + // input to MPCC is always RGB, by default leave black_color at 0 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) - hws->funcs.get_hdr_visual_confirm_color(pipe_ctx, color); + get_hdr_visual_confirm_color(pipe_ctx, color); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) - hws->funcs.get_surface_visual_confirm_color(pipe_ctx, color); + get_surface_visual_confirm_color(pipe_ctx, color); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE) - dcn20_get_mpctree_visual_confirm_color(pipe_ctx, color); + get_mpctree_visual_confirm_color(pipe_ctx, color); + else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE) + get_surface_tile_visual_confirm_color(pipe_ctx, color); if (mpc->funcs->set_bg_color) mpc->funcs->set_bg_color(mpc, color, mpcc_id); @@ -2327,12 +2328,11 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) */ mpcc_id = hubp->inst; - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); - /* If there is no full update, don't need to touch MPC tree*/ if (!pipe_ctx->plane_state->update_flags.bits.full_update && !pipe_ctx->update_flags.bits.mpcc) { mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); return; } @@ -2354,6 +2354,7 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) NULL, hubp->inst, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); ASSERT(new_mpcc != NULL); hubp->opp_id = pipe_ctx->stream_res.opp->inst; @@ -2548,6 +2549,9 @@ void dcn20_fpga_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } + + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); } #ifndef TRIM_FSFT bool dcn20_optimize_timing_for_fsft(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index 2f59f10e5f09..5cfd4b0afea5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -96,7 +96,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = { #endif .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .update_visual_confirm_color = dcn20_update_visual_confirm_color, + .update_visual_confirm_color = dcn20_update_visual_confirm_color }; static const struct hwseq_private_funcs dcn20_private_funcs = { @@ -126,8 +126,6 @@ static const struct hwseq_private_funcs dcn20_private_funcs = { .hubp_pg_control = dcn20_hubp_pg_control, .update_odm = dcn20_update_odm, .dsc_pg_control = dcn20_dsc_pg_control, - .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, - .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, .wait_for_blank_complete = dcn20_wait_for_blank_complete, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c index 3139d90017ee..7fa9fc656b0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c @@ -520,6 +520,14 @@ bool optc2_configure_crc(struct timing_generator *optc, return optc1_configure_crc(optc, params); } + +void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, uint32_t *refresh_rate) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, refresh_rate); +} + static struct timing_generator_funcs dcn20_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, @@ -553,6 +561,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, .enable_optc_clock = optc1_enable_optc_clock, .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, .set_static_screen_control = optc1_set_static_screen_control, .program_stereo = optc1_program_stereo, .is_stereo_left_eye = optc1_is_stereo_left_eye, @@ -591,4 +600,3 @@ void dcn20_timing_generator_init(struct optc *optc1) optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. optc1->min_v_sync_width = 1; } - diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h index 3dee2ec2a1bb..be19a6885fbf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h @@ -42,7 +42,8 @@ SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ SR(DWB_SOURCE_SELECT),\ - SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst), \ + SRI(OTG_DRR_CONTROL, OTG, inst) #define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ @@ -75,10 +76,14 @@ SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh) + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh), \ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) void dcn20_timing_generator_init(struct optc *optc); +void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, + uint32_t *refresh_rate); + bool optc2_enable_crtc(struct timing_generator *optc); void optc2_set_gsl(struct timing_generator *optc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 6a56a03cfba3..1b05a37b674d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1065,7 +1065,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -2289,12 +2289,14 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90 || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz; - pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport_unadjusted.y; - pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c_unadjusted.y; - pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport_unadjusted.width; - pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c_unadjusted.width; - pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport_unadjusted.height; - pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c_unadjusted.height; + pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; + pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y; + pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport.width; + pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width; + pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height; + pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height; + pipes[pipe_cnt].pipe.src.viewport_width_max = pln->src_rect.width; + pipes[pipe_cnt].pipe.src.viewport_height_max = pln->src_rect.height; pipes[pipe_cnt].pipe.src.surface_width_y = pln->plane_size.surface_size.width; pipes[pipe_cnt].pipe.src.surface_height_y = pln->plane_size.surface_size.height; pipes[pipe_cnt].pipe.src.surface_width_c = pln->plane_size.chroma_size.width; @@ -2363,6 +2365,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.source_format = dm_420_10; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: pipes[pipe_cnt].pipe.src.source_format = dm_444_64; @@ -2786,7 +2789,6 @@ int dcn20_validate_apply_pipe_split_flags( split[i] = 0; } else if (get_num_odm_splits(pipe)) { /* ODM -> MPC transition */ - ASSERT(0); /* NOT expected yet */ if (pipe->prev_odm_pipe) { split[i] = 0; merge[i] = true; @@ -3067,6 +3069,16 @@ static void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; } +static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) +{ + int i; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + } + return false; +} + void dcn20_calculate_dlg_params( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, @@ -3074,6 +3086,7 @@ void dcn20_calculate_dlg_params( int vlevel) { int i, pipe_idx; + int plane_count; /* Writeback MCIF_WB arbitration parameters */ dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt); @@ -3089,6 +3102,20 @@ void dcn20_calculate_dlg_params( != dm_dram_clock_change_unsupported; context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; + context->bw_ctx.bw.dcn.clk.z9_support = (context->bw_ctx.dml.vba.StutterPeriod > 5000.0) ? + DCN_Z9_SUPPORT_ALLOW : DCN_Z9_SUPPORT_DISALLOW; + + plane_count = 0; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].plane_state) + plane_count++; + } + + if (plane_count == 0) + context->bw_ctx.bw.dcn.clk.z9_support = DCN_Z9_SUPPORT_ALLOW; + + context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context); + if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz) context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz; @@ -3099,6 +3126,9 @@ void dcn20_calculate_dlg_params( pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + context->res_ctx.pipe_ctx[i].det_buffer_size_kb = context->bw_ctx.dml.ip.det_buffer_size_kbytes; + context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode; + if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = @@ -3112,6 +3142,9 @@ void dcn20_calculate_dlg_params( context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz * 1000; context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000; + context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes + - context->bw_ctx.dml.ip.det_buffer_size_kbytes * pipe_idx; + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { bool cstate_en = context->bw_ctx.dml.vba.PrefetchMode[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != 2; @@ -3236,7 +3269,7 @@ static noinline bool dcn20_validate_bandwidth_fp(struct dc *dc, voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; - if (voltage_supported && dummy_pstate_supported) { + if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { context->bw_ctx.bw.dcn.clk.p_state_change_support = false; goto restore_dml_state; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c index 4075ae111530..e6307397e0d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -552,6 +552,17 @@ void enc2_stream_encoder_dp_set_stream_attribute( DP_SST_SDP_SPLITTING, enable_sdp_splitting); } +uint32_t enc2_get_fifo_cal_average_level( + struct stream_encoder *enc) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t fifo_level; + + REG_GET(DIG_FIFO_STATUS, + DIG_FIFO_CAL_AVERAGE_LEVEL, &fifo_level); + return fifo_level; +} + static const struct stream_encoder_funcs dcn20_str_enc_funcs = { .dp_set_odm_combine = enc2_dp_set_odm_combine, @@ -598,6 +609,7 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { .dp_set_dsc_pps_info_packet = enc2_dp_set_dsc_pps_info_packet, .set_dynamic_metadata = enc2_set_dynamic_metadata, .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, + .get_fifo_cal_average_level = enc2_get_fifo_cal_average_level, }; void dcn20_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h index 9a881e639709..f3d1a0237bda 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h @@ -112,4 +112,7 @@ void enc2_set_dynamic_metadata(struct stream_encoder *enc, uint32_t hubp_requestor_id, enum dynamic_metadata_mode dmdata_mode); +uint32_t enc2_get_fifo_cal_average_level( + struct stream_encoder *enc); + #endif /* __DC_STREAM_ENCODER_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_dccg.c index 60cf3ff68cb0..33fc9aa8621b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_dccg.c @@ -100,6 +100,9 @@ void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) static const struct dccg_funcs dccg21_funcs = { .update_dpp_dto = dccg21_update_dpp_dto, .get_dccg_ref_freq = dccg2_get_dccg_ref_freq, + .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, + .otg_add_pixel = dccg2_otg_add_pixel, + .otg_drop_pixel = dccg2_otg_drop_pixel, .dccg_init = dccg2_init }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index 523e25f7e410..54c11ba550ae 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -130,8 +130,6 @@ static const struct hwseq_private_funcs dcn21_private_funcs = { .hubp_pg_control = dcn20_hubp_pg_control, .update_odm = dcn20_update_odm, .dsc_pg_control = dcn20_dsc_pg_control, - .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, - .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, .s0i3_golden_init_wa = dcn21_s0i3_golden_init_wa, diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index 38a2aa87f5f5..f3d98e3ba624 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -448,11 +448,11 @@ static const struct dccg_registers dccg_regs = { }; static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN2(__SHIFT) + DCCG_MASK_SH_LIST_DCN2_1(__SHIFT) }; static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN2(_MASK) + DCCG_MASK_SH_LIST_DCN2_1(_MASK) }; #define opp_regs(id)\ @@ -1575,12 +1575,10 @@ static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_li low_pstate_lvl.phyclk_d18_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_d18_mhz; low_pstate_lvl.phyclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_mhz; - if (clk_table->num_entries < MAX_NUM_DPM_LVL) { - for (i = clk_table->num_entries; i > 1; i--) - clk_table->entries[i] = clk_table->entries[i-1]; - clk_table->entries[1] = clk_table->entries[0]; - clk_table->num_entries++; - } + for (i = clk_table->num_entries; i > 1; i--) + clk_table->entries[i] = clk_table->entries[i-1]; + clk_table->entries[1] = clk_table->entries[0]; + clk_table->num_entries++; return low_pstate_lvl; } @@ -1612,6 +1610,10 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param } } + /* clk_table[1] is reserved for min DF PState. skip here to fill in later. */ + if (i == 1) + k++; + clock_limits[k].state = k; clock_limits[k].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; clock_limits[k].fabricclk_mhz = clk_table->entries[i].fclk_mhz; @@ -1628,25 +1630,14 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param k++; } - - if (clk_table->num_entries >= MAX_NUM_DPM_LVL) { - for (i = 0; i < clk_table->num_entries + 1; i++) - dcn2_1_soc.clock_limits[i] = clock_limits[i]; - } else { - dcn2_1_soc.clock_limits[0] = clock_limits[0]; - for (i = 2; i < clk_table->num_entries + 1; i++) { - dcn2_1_soc.clock_limits[i] = clock_limits[i - 1]; - dcn2_1_soc.clock_limits[i].state = i; - } - } - + for (i = 0; i < clk_table->num_entries + 1; i++) + dcn2_1_soc.clock_limits[i] = clock_limits[i]; if (clk_table->num_entries) { + dcn2_1_soc.num_states = clk_table->num_entries + 1; /* fill in min DF PState */ dcn2_1_soc.clock_limits[1] = construct_low_pstate_lvl(clk_table, closest_clk_lvl); - dcn2_1_soc.num_states = clk_table->num_entries; /* duplicate last level */ - dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = - dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1]; + dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1]; dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.c index b822a13e40ce..d445dfefc047 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.c @@ -46,6 +46,9 @@ static const struct dccg_funcs dccg3_funcs = { .update_dpp_dto = dccg2_update_dpp_dto, .get_dccg_ref_freq = dccg2_get_dccg_ref_freq, + .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, + .otg_add_pixel = dccg2_otg_add_pixel, + .otg_drop_pixel = dccg2_otg_drop_pixel, .dccg_init = dccg2_init }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.h index 029dda13a464..35a613bb08bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dccg.h @@ -38,10 +38,25 @@ #define DCCG_REG_LIST_DCN30() \ DCCG_REG_LIST_DCN2(),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 4),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 5),\ SR(PHYASYMCLK_CLOCK_CNTL),\ SR(PHYBSYMCLK_CLOCK_CNTL),\ SR(PHYCSYMCLK_CLOCK_CNTL) +#define DCCG_MASK_SH_LIST_DCN3AG(mask_sh) \ + DCCG_MASK_SH_LIST_DCN2_1(mask_sh),\ + DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_EN, mask_sh),\ + DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_SRC_SEL, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh) + #define DCCG_MASK_SH_LIST_DCN3(mask_sh) \ DCCG_MASK_SH_LIST_DCN2(mask_sh),\ DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_EN, mask_sh),\ @@ -49,7 +64,7 @@ DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_EN, mask_sh),\ DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_SRC_SEL, mask_sh),\ DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh) + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh),\ struct dccg *dccg3_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c index 72bee637c1e4..8487516819ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c @@ -823,6 +823,8 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = { .dp_set_dsc_pps_info_packet = enc3_dp_set_dsc_pps_info_packet, .set_dynamic_metadata = enc2_set_dynamic_metadata, .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, + + .get_fifo_cal_average_level = enc2_get_fifo_cal_average_level, }; void dcn30_dio_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h index 9566b9037458..e2c264ecb20f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h @@ -106,6 +106,7 @@ SRI(DP_SEC_METADATA_TRANSMISSION, DP, id), \ SRI(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ SRI(DIG_FE_CNTL, DIG, id), \ + SRI(DIG_FIFO_STATUS, DIG, id), \ SRI(DIG_CLOCK_PATTERN, DIG, id) @@ -167,6 +168,17 @@ SE_SF(DIG0_DIG_FE_CNTL, TMDS_COLOR_FORMAT, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_LEVEL_ERROR, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_USE_OVERWRITE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_OVERWRITE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_ERROR_ACK, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_CAL_AVERAGE_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_MAXIMUM_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_MINIMUM_LEVEL, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_READ_CLOCK_SRC, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_CALIBRATED, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_FORCE_RECAL_AVERAGE, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_STATUS, DIG_FIFO_FORCE_RECOMP_MINMAX, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP4_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP6_ENABLE, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c index 434d3c46cad4..2140b75540cf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c @@ -245,7 +245,8 @@ static void dpp3_cnv_setup ( select = INPUT_CSC_SELECT_ICSC; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: - pixel_format = 22; + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: + pixel_format = 26; /* ARGB16161616_UNORM */ break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: pixel_format = 24; @@ -1442,7 +1443,8 @@ bool dpp3_construct( dpp->lb_pixel_depth_supported = LB_PIXEL_DEPTH_18BPP | LB_PIXEL_DEPTH_24BPP | - LB_PIXEL_DEPTH_30BPP; + LB_PIXEL_DEPTH_30BPP | + LB_PIXEL_DEPTH_36BPP; dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 83685310a391..c68e3a708a33 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -48,6 +48,8 @@ #include "dc_dmub_srv.h" #include "link_hwss.h" #include "dpcd_defs.h" +#include "inc/dc_link_dp.h" +#include "inc/link_dpcd.h" @@ -529,6 +531,8 @@ void dcn30_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) continue; + /* DP 2.0 states that LTTPR regs must be read first */ + dp_retrieve_lttpr_cap(dc->links[i]); /* if any of the displays are lit up turn them off */ status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, @@ -651,6 +655,9 @@ void dcn30_init_hw(struct dc *dc) if (dc->res_pool->hubbub->funcs->force_pstate_change_control) dc->res_pool->hubbub->funcs->force_pstate_change_control( dc->res_pool->hubbub, false, false); + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); + } void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c index a978d848d370..3a5b53dd2f6d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c @@ -130,8 +130,6 @@ static const struct hwseq_private_funcs dcn30_private_funcs = { .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn20_update_odm, .dsc_pg_control = dcn20_dsc_pg_control, - .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, - .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, .wait_for_blank_complete = dcn20_wait_for_blank_complete, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c index ac478bdcfb2a..f37e8254df21 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c @@ -315,6 +315,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, .enable_optc_clock = optc1_enable_optc_clock, .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, .set_static_screen_control = optc1_set_static_screen_control, .program_stereo = optc1_program_stereo, .is_stereo_left_eye = optc1_is_stereo_left_eye, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h index 379616831636..736e63bc80c2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h @@ -87,7 +87,8 @@ SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ SR(GSL_SOURCE_SELECT),\ - SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI(OTG_DRR_CONTROL, OTG, inst) #define OPTC_COMMON_REG_LIST_DCN3_0(inst) \ @@ -233,7 +234,8 @@ SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh) + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) #define OPTC_COMMON_MASK_SH_LIST_DCN3_0(mask_sh)\ OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 39920422409d..596c97dce67e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -840,7 +840,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dccg.c index 420da414929c..97e9be87afd9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dccg.c @@ -45,6 +45,9 @@ static const struct dccg_funcs dccg301_funcs = { .update_dpp_dto = dccg2_update_dpp_dto, .get_dccg_ref_freq = dccg2_get_dccg_ref_freq, + .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, + .otg_add_pixel = dccg2_otg_add_pixel, + .otg_drop_pixel = dccg2_otg_drop_pixel, .dccg_init = dccg2_init }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c index 181f2175ac95..e85b695f2351 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c @@ -132,8 +132,6 @@ static const struct hwseq_private_funcs dcn301_private_funcs = { .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn20_update_odm, .dsc_pg_control = dcn20_dsc_pg_control, - .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, - .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, .wait_for_blank_complete = dcn20_wait_for_blank_complete, diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c index e8580cccbebf..0a6d58dd8f6d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c @@ -86,17 +86,12 @@ void dcn302_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool po 1, 1000); break; case 4: /* DPP4 */ - /* - * Do not power gate DPP4, should be left at HW default, power on permanently. - * PG on Pipe4 is De-featured, attempting to put it to PG state may result in hard - * reset. - * REG_UPDATE(DOMAIN9_PG_CONFIG, - * DOMAIN9_POWER_GATE, power_gate); - * - * REG_WAIT(DOMAIN9_PG_STATUS, - * DOMAIN9_PGFSM_PWR_STATUS, pwr_status, - * 1, 1000); - */ + REG_UPDATE(DOMAIN9_PG_CONFIG, + DOMAIN9_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN9_PG_STATUS, + DOMAIN9_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); break; default: BREAK_TO_DEBUGGER(); @@ -148,17 +143,12 @@ void dcn302_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool 1, 1000); break; case 4: /* DCHUBP4 */ - /* - * Do not power gate DCHUB4, should be left at HW default, power on permanently. - * PG on Pipe4 is De-featured, attempting to put it to PG state may result in hard - * reset. - * REG_UPDATE(DOMAIN8_PG_CONFIG, - * DOMAIN8_POWER_GATE, power_gate); - * - * REG_WAIT(DOMAIN8_PG_STATUS, - * DOMAIN8_PGFSM_PWR_STATUS, pwr_status, - * 1, 1000); - */ + REG_UPDATE(DOMAIN8_PG_CONFIG, + DOMAIN8_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN8_PG_STATUS, + DOMAIN8_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); break; default: BREAK_TO_DEBUGGER(); diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index 00cb6d11ed0d..16a75ba0ca82 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -164,8 +164,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc = { .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */ .num_states = 1, - .sr_exit_time_us = 15.5, - .sr_enter_plus_exit_time_us = 20, + .sr_exit_time_us = 26.5, + .sr_enter_plus_exit_time_us = 31, .urgent_latency_us = 4.0, .urgent_latency_pixel_data_only_us = 4.0, .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, @@ -211,7 +211,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -1102,6 +1102,26 @@ static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) loaded_ip->max_num_dpp = pool->pipe_count; loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; dcn20_patch_bounding_box(dc, loaded_bb); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = { 0 }; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info( + dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { + if (bb_info.dram_clock_change_latency_100ns > 0) + dcn3_02_soc.dram_clock_change_latency_us = + bb_info.dram_clock_change_latency_100ns * 10; + + if (bb_info.dram_sr_enter_exit_latency_100ns > 0) + dcn3_02_soc.sr_enter_plus_exit_time_us = + bb_info.dram_sr_enter_exit_latency_100ns * 10; + + if (bb_info.dram_sr_exit_latency_100ns > 0) + dcn3_02_soc.sr_exit_time_us = + bb_info.dram_sr_exit_latency_100ns * 10; + } + } + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c index dc33ec8b7bdb..b48b732aa647 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c @@ -38,3 +38,8 @@ void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool po { /*DCN303 removes PG registers*/ } + +void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) +{ + /*DCN303 removes PG registers*/ +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h index fc6cab720b6d..8b69a3b76c11 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h @@ -13,5 +13,6 @@ void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); +void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); #endif /* __DC_HWSS_DCN303_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c index 86d4b303d02f..aa5dbbade2bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c @@ -16,4 +16,5 @@ void dcn303_hw_sequencer_construct(struct dc *dc) dc->hwseq->funcs.dpp_pg_control = dcn303_dpp_pg_control; dc->hwseq->funcs.hubp_pg_control = dcn303_hubp_pg_control; dc->hwseq->funcs.dsc_pg_control = dcn303_dsc_pg_control; + dc->hwseq->funcs.enable_power_gating_plane = dcn303_enable_power_gating_plane; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index aff0230c9193..34b89464ae02 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -146,8 +146,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc = { .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */ .num_states = 1, - .sr_exit_time_us = 15.5, - .sr_enter_plus_exit_time_us = 20, + .sr_exit_time_us = 26.5, + .sr_enter_plus_exit_time_us = 31, .urgent_latency_us = 4.0, .urgent_latency_pixel_data_only_us = 4.0, .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, @@ -193,7 +193,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -1028,6 +1028,26 @@ static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) loaded_ip->max_num_dpp = pool->pipe_count; loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; dcn20_patch_bounding_box(dc, loaded_bb); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = { 0 }; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info( + dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { + if (bb_info.dram_clock_change_latency_100ns > 0) + dcn3_03_soc.dram_clock_change_latency_us = + bb_info.dram_clock_change_latency_100ns * 10; + + if (bb_info.dram_sr_enter_exit_latency_100ns > 0) + dcn3_03_soc.sr_enter_plus_exit_time_us = + bb_info.dram_sr_enter_exit_latency_100ns * 10; + + if (bb_info.dram_sr_exit_latency_100ns > 0) + dcn3_03_soc.sr_exit_time_us = + bb_info.dram_sr_exit_latency_100ns * 10; + } + } + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile new file mode 100644 index 000000000000..5dcdc5a858fe --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -0,0 +1,42 @@ +# +# (c) Copyright 2020 Advanced Micro Devices, Inc. All the rights reserved +# +# All rights reserved. This notice is intended as a precaution against +# inadvertent publication and does not imply publication or any waiver +# of confidentiality. The year included in the foregoing notice is the +# year of creation of the work. +# +# Authors: AMD +# +# Makefile for dcn31. + +DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \ + dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o + +ifdef CONFIG_X86 +CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse +endif + +ifdef CONFIG_PPC64 +CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -mhard-float -maltivec +endif + +ifdef CONFIG_CC_IS_GCC +ifeq ($(call cc-ifversion, -lt, 0701, y), y) +IS_OLD_GCC = 1 +endif +CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mhard-float +endif + +ifdef IS_OLD_GCC +# Stack alignment mismatch, proceed with caution. +# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 +# (8B stack alignment). +CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mpreferred-stack-boundary=4 +else +CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -msse2 +endif + +AMD_DAL_DCN31 = $(addprefix $(AMDDALPATH)/dc/dcn31/,$(DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCN31) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c new file mode 100644 index 000000000000..696c9307715d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -0,0 +1,279 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "reg_helper.h" +#include "core_types.h" +#include "dcn31_dccg.h" + +#define TO_DCN_DCCG(dccg)\ + container_of(dccg, struct dcn_dccg, base) + +#define REG(reg) \ + (dccg_dcn->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name + +#define CTX \ + dccg_dcn->base.ctx +#define DC_LOGGER \ + dccg->ctx->logger + +void dccg31_set_physymclk( + struct dccg *dccg, + int phy_inst, + enum physymclk_clock_source clk_src, + bool force_enable) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + /* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */ + switch (phy_inst) { + case 0: + if (force_enable) + REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL, + PHYASYMCLK_FORCE_EN, 1, + PHYASYMCLK_FORCE_SRC_SEL, clk_src); + else + REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL, + PHYASYMCLK_FORCE_EN, 0, + PHYASYMCLK_FORCE_SRC_SEL, 0); + break; + case 1: + if (force_enable) + REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL, + PHYBSYMCLK_FORCE_EN, 1, + PHYBSYMCLK_FORCE_SRC_SEL, clk_src); + else + REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL, + PHYBSYMCLK_FORCE_EN, 0, + PHYBSYMCLK_FORCE_SRC_SEL, 0); + break; + case 2: + if (force_enable) + REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL, + PHYCSYMCLK_FORCE_EN, 1, + PHYCSYMCLK_FORCE_SRC_SEL, clk_src); + else + REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL, + PHYCSYMCLK_FORCE_EN, 0, + PHYCSYMCLK_FORCE_SRC_SEL, 0); + break; + case 3: + if (force_enable) + REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL, + PHYDSYMCLK_FORCE_EN, 1, + PHYDSYMCLK_FORCE_SRC_SEL, clk_src); + else + REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL, + PHYDSYMCLK_FORCE_EN, 0, + PHYDSYMCLK_FORCE_SRC_SEL, 0); + break; + case 4: + if (force_enable) + REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL, + PHYESYMCLK_FORCE_EN, 1, + PHYESYMCLK_FORCE_SRC_SEL, clk_src); + else + REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL, + PHYESYMCLK_FORCE_EN, 0, + PHYESYMCLK_FORCE_SRC_SEL, 0); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + +/* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */ +void dccg31_set_dtbclk_dto( + struct dccg *dccg, + int dtbclk_inst, + int req_dtbclk_khz, + int num_odm_segments, + const struct dc_crtc_timing *timing) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t dtbdto_div; + + /* Mode DTBDTO Rate DTBCLK_DTO<x>_DIV Register + * ODM 4:1 combine pixel rate/4 2 + * ODM 2:1 combine pixel rate/2 4 + * non-DSC 4:2:0 mode pixel rate/2 4 + * DSC native 4:2:0 pixel rate/2 4 + * DSC native 4:2:2 pixel rate/2 4 + * Other modes pixel rate 8 + */ + if (num_odm_segments == 4) { + dtbdto_div = 2; + req_dtbclk_khz = req_dtbclk_khz / 4; + } else if ((num_odm_segments == 2) || + (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) || + (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 + && !timing->dsc_cfg.ycbcr422_simple)) { + dtbdto_div = 4; + req_dtbclk_khz = req_dtbclk_khz / 2; + } else + dtbdto_div = 8; + + if (dccg->ref_dtbclk_khz && req_dtbclk_khz) { + uint32_t modulo, phase; + + // phase / modulo = dtbclk / dtbclk ref + modulo = dccg->ref_dtbclk_khz * 1000; + phase = div_u64((((unsigned long long)modulo * req_dtbclk_khz) + dccg->ref_dtbclk_khz - 1), + dccg->ref_dtbclk_khz); + + REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst], + DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div); + + REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], modulo); + REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], phase); + + REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst], + DTBCLK_DTO_ENABLE[dtbclk_inst], 1); + + REG_WAIT(OTG_PIXEL_RATE_CNTL[dtbclk_inst], + DTBCLKDTO_ENABLE_STATUS[dtbclk_inst], 1, + 1, 100); + + /* The recommended programming sequence to enable DTBCLK DTO to generate + * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should + * be set only after DTO is enabled + */ + REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst], + PIPE_DTO_SRC_SEL[dtbclk_inst], 1); + + dccg->dtbclk_khz[dtbclk_inst] = req_dtbclk_khz; + } else { + REG_UPDATE_3(OTG_PIXEL_RATE_CNTL[dtbclk_inst], + DTBCLK_DTO_ENABLE[dtbclk_inst], 0, + PIPE_DTO_SRC_SEL[dtbclk_inst], 0, + DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div); + + REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], 0); + REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], 0); + + dccg->dtbclk_khz[dtbclk_inst] = 0; + } +} + +void dccg31_set_audio_dtbclk_dto( + struct dccg *dccg, + uint32_t req_audio_dtbclk_khz) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (dccg->ref_dtbclk_khz && req_audio_dtbclk_khz) { + uint32_t modulo, phase; + + // phase / modulo = dtbclk / dtbclk ref + modulo = dccg->ref_dtbclk_khz * 1000; + phase = div_u64((((unsigned long long)modulo * req_audio_dtbclk_khz) + dccg->ref_dtbclk_khz - 1), + dccg->ref_dtbclk_khz); + + + REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, modulo); + REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, phase); + + //REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, + // DCCG_AUDIO_DTBCLK_DTO_USE_512FBR_DTO, 1); + + REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, + DCCG_AUDIO_DTO_SEL, 4); // 04 - DCCG_AUDIO_DTO_SEL_AUDIO_DTO_DTBCLK + + dccg->audio_dtbclk_khz = req_audio_dtbclk_khz; + } else { + REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, 0); + REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, 0); + + REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, + DCCG_AUDIO_DTO_SEL, 3); // 03 - DCCG_AUDIO_DTO_SEL_NO_AUDIO_DTO + + dccg->audio_dtbclk_khz = 0; + } +} + +static void dccg31_get_dccg_ref_freq(struct dccg *dccg, + unsigned int xtalin_freq_inKhz, + unsigned int *dccg_ref_freq_inKhz) +{ + /* + * Assume refclk is sourced from xtalin + * expect 24MHz + */ + *dccg_ref_freq_inKhz = xtalin_freq_inKhz; + return; +} + +static void dccg31_set_dispclk_change_mode( + struct dccg *dccg, + enum dentist_dispclk_change_mode change_mode) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE, + change_mode == DISPCLK_CHANGE_MODE_RAMPING ? 2 : 0); +} + +void dccg31_init(struct dccg *dccg) +{ +} + +static const struct dccg_funcs dccg31_funcs = { + .update_dpp_dto = dccg2_update_dpp_dto, + .get_dccg_ref_freq = dccg31_get_dccg_ref_freq, + .dccg_init = dccg31_init, + .set_physymclk = dccg31_set_physymclk, + .set_dtbclk_dto = dccg31_set_dtbclk_dto, + .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto, + .set_dispclk_change_mode = dccg31_set_dispclk_change_mode, +}; + +struct dccg *dccg31_create( + struct dc_context *ctx, + const struct dccg_registers *regs, + const struct dccg_shift *dccg_shift, + const struct dccg_mask *dccg_mask) +{ + struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL); + struct dccg *base; + + if (dccg_dcn == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + base = &dccg_dcn->base; + base->ctx = ctx; + base->funcs = &dccg31_funcs; + + dccg_dcn->regs = regs; + dccg_dcn->dccg_shift = dccg_shift; + dccg_dcn->dccg_mask = dccg_mask; + + return &dccg_dcn->base; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h new file mode 100644 index 000000000000..706ad80ba873 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h @@ -0,0 +1,147 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DCN31_DCCG_H__ +#define __DCN31_DCCG_H__ + +#include "dcn30/dcn30_dccg.h" + +#define DCCG_SFII(block, reg_name, field_prefix, field_name, inst, post_fix)\ + .field_prefix ## _ ## field_name[inst] = block ## inst ## _ ## reg_name ## __ ## field_prefix ## inst ## _ ## field_name ## post_fix + + +#define DCCG_REG_LIST_DCN31() \ + SR(DPPCLK_DTO_CTRL),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 0),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 1),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 2),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 3),\ + SR(PHYASYMCLK_CLOCK_CNTL),\ + SR(PHYBSYMCLK_CLOCK_CNTL),\ + SR(PHYCSYMCLK_CLOCK_CNTL),\ + SR(PHYDSYMCLK_CLOCK_CNTL),\ + SR(PHYESYMCLK_CLOCK_CNTL),\ + SR(DPSTREAMCLK_CNTL),\ + SR(SYMCLK32_SE_CNTL),\ + SR(SYMCLK32_LE_CNTL),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3),\ + DCCG_SRII(MODULO, DTBCLK_DTO, 0),\ + DCCG_SRII(MODULO, DTBCLK_DTO, 1),\ + DCCG_SRII(MODULO, DTBCLK_DTO, 2),\ + DCCG_SRII(MODULO, DTBCLK_DTO, 3),\ + DCCG_SRII(PHASE, DTBCLK_DTO, 0),\ + DCCG_SRII(PHASE, DTBCLK_DTO, 1),\ + DCCG_SRII(PHASE, DTBCLK_DTO, 2),\ + DCCG_SRII(PHASE, DTBCLK_DTO, 3),\ + SR(DCCG_AUDIO_DTBCLK_DTO_MODULO),\ + SR(DCCG_AUDIO_DTBCLK_DTO_PHASE),\ + SR(DCCG_AUDIO_DTO_SOURCE),\ + SR(DENTIST_DISPCLK_CNTL) + + +#define DCCG_MASK_SH_LIST_DCN31(mask_sh) \ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 1, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 2, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 3, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\ + DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK_PIPE0_EN, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK_PIPE1_EN, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK_PIPE2_EN, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK_PIPE3_EN, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_EN, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_EN, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_EN, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_EN, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_EN, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_EN, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, ENABLE, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, ENABLE, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, ENABLE, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, ENABLE, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLKDTO, ENABLE_STATUS, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLKDTO, ENABLE_STATUS, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLKDTO, ENABLE_STATUS, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLKDTO, ENABLE_STATUS, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 3, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, DIV, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, DIV, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, DIV, 2, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, DIV, 3, mask_sh),\ + DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\ + DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\ + DCCG_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE, mask_sh) + + +struct dccg *dccg31_create( + struct dc_context *ctx, + const struct dccg_registers *regs, + const struct dccg_shift *dccg_shift, + const struct dccg_mask *dccg_mask); + +void dccg31_init(struct dccg *dccg); + +void dccg31_set_physymclk( + struct dccg *dccg, + int phy_inst, + enum physymclk_clock_source clk_src, + bool force_enable); + +void dccg31_set_audio_dtbclk_dto( + struct dccg *dccg, + uint32_t req_audio_dtbclk_khz); + +void dccg31_set_hdmistreamclk( + struct dccg *dccg, + enum hdmistreamclk_source src); + +#endif //__DCN31_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c new file mode 100644 index 000000000000..90127c1f9e35 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -0,0 +1,406 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "reg_helper.h" + +#include "core_types.h" +#include "link_encoder.h" +#include "dcn31_dio_link_encoder.h" +#include "stream_encoder.h" +#include "i2caux_interface.h" +#include "dc_bios_types.h" + +#include "gpio_service_interface.h" + +#include "link_enc_cfg.h" +#include "dc_dmub_srv.h" + +#define CTX \ + enc10->base.ctx +#define DC_LOGGER \ + enc10->base.ctx->logger + +#define REG(reg)\ + (enc10->link_regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + enc10->link_shift->field_name, enc10->link_mask->field_name + +#define IND_REG(index) \ + (enc10->link_regs->index) + +#define AUX_REG(reg)\ + (enc10->aux_regs->reg) + +#define AUX_REG_READ(reg_name) \ + dm_read_reg(CTX, AUX_REG(reg_name)) + +#define AUX_REG_WRITE(reg_name, val) \ + dm_write_reg(CTX, AUX_REG(reg_name), val) + +void dcn31_link_encoder_set_dio_phy_mux( + struct link_encoder *enc, + enum encoder_type_select sel, + uint32_t hpo_inst) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + + switch (enc->transmitter) { + case TRANSMITTER_UNIPHY_A: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKA_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKA_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKA_CNTL, + ENC_TYPE_SEL, sel); + break; + case TRANSMITTER_UNIPHY_B: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKB_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKB_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKB_CNTL, + ENC_TYPE_SEL, sel); + break; + case TRANSMITTER_UNIPHY_C: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKC_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKC_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKC_CNTL, + ENC_TYPE_SEL, sel); + break; + case TRANSMITTER_UNIPHY_D: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKD_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKD_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKD_CNTL, + ENC_TYPE_SEL, sel); + break; + case TRANSMITTER_UNIPHY_E: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKE_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKE_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKE_CNTL, + ENC_TYPE_SEL, sel); + break; + case TRANSMITTER_UNIPHY_F: + if (sel == ENCODER_TYPE_HDMI_FRL) + REG_UPDATE(DIO_LINKF_CNTL, + HPO_HDMI_ENC_SEL, hpo_inst); + else if (sel == ENCODER_TYPE_DP_128B132B) + REG_UPDATE(DIO_LINKF_CNTL, + HPO_DP_ENC_SEL, hpo_inst); + REG_UPDATE(DIO_LINKF_CNTL, + ENC_TYPE_SEL, sel); + break; + default: + /* Do nothing */ + break; + } +} + +void enc31_hw_init(struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + +/* + 00 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__1to2 : 1/2 + 01 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__3to4 : 3/4 + 02 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__7to8 : 7/8 + 03 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__15to16 : 15/16 + 04 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__31to32 : 31/32 + 05 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__63to64 : 63/64 + 06 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__127to128 : 127/128 + 07 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__255to256 : 255/256 +*/ + +/* + AUX_REG_UPDATE_5(AUX_DPHY_RX_CONTROL0, + AUX_RX_START_WINDOW = 1 [6:4] + AUX_RX_RECEIVE_WINDOW = 1 default is 2 [10:8] + AUX_RX_HALF_SYM_DETECT_LEN = 1 [13:12] default is 1 + AUX_RX_TRANSITION_FILTER_EN = 1 [16] default is 1 + AUX_RX_ALLOW_BELOW_THRESHOLD_PHASE_DETECT [17] is 0 default is 0 + AUX_RX_ALLOW_BELOW_THRESHOLD_START [18] is 1 default is 1 + AUX_RX_ALLOW_BELOW_THRESHOLD_STOP [19] is 1 default is 1 + AUX_RX_PHASE_DETECT_LEN, [21,20] = 0x3 default is 3 + AUX_RX_DETECTION_THRESHOLD [30:28] = 1 +*/ + AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110); + + AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a); + + //AUX_DPHY_TX_REF_CONTROL'AUX_TX_REF_DIV HW default is 0x32; + // Set AUX_TX_REF_DIV Divider to generate 2 MHz reference from refclk + // 27MHz -> 0xd + // 100MHz -> 0x32 + // 48MHz -> 0x18 + +#ifdef CLEANUP_FIXME + /*from display_init*/ + REG_WRITE(RDPCSTX_DEBUG_CONFIG, 0); +#endif + + // Set TMDS_CTL0 to 1. This is a legacy setting. + REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1); + + /*HW default is 5*/ + REG_UPDATE(RDPCSTX_CNTL, + RDPCS_TX_FIFO_RD_START_DELAY, 4); + + dcn10_aux_initialize(enc10); +} + +static const struct link_encoder_funcs dcn31_link_enc_funcs = { + .read_state = link_enc2_read_state, + .validate_output_with_stream = + dcn30_link_encoder_validate_output_with_stream, + .hw_init = enc31_hw_init, + .setup = dcn10_link_encoder_setup, + .enable_tmds_output = dcn10_link_encoder_enable_tmds_output, + .enable_dp_output = dcn31_link_encoder_enable_dp_output, + .enable_dp_mst_output = dcn31_link_encoder_enable_dp_mst_output, + .disable_output = dcn31_link_encoder_disable_output, + .dp_set_lane_settings = dcn10_link_encoder_dp_set_lane_settings, + .dp_set_phy_pattern = dcn10_link_encoder_dp_set_phy_pattern, + .update_mst_stream_allocation_table = + dcn10_link_encoder_update_mst_stream_allocation_table, + .psr_program_dp_dphy_fast_training = + dcn10_psr_program_dp_dphy_fast_training, + .psr_program_secondary_packet = dcn10_psr_program_secondary_packet, + .connect_dig_be_to_fe = dcn10_link_encoder_connect_dig_be_to_fe, + .enable_hpd = dcn10_link_encoder_enable_hpd, + .disable_hpd = dcn10_link_encoder_disable_hpd, + .is_dig_enabled = dcn10_is_dig_enabled, + .destroy = dcn10_link_encoder_destroy, + .fec_set_enable = enc2_fec_set_enable, + .fec_set_ready = enc2_fec_set_ready, + .fec_is_active = enc2_fec_is_active, + .get_dig_frontend = dcn10_get_dig_frontend, + .get_dig_mode = dcn10_get_dig_mode, + .is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode, + .get_max_link_cap = dcn20_link_encoder_get_max_link_cap, + .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux, +}; + +void dcn31_link_encoder_construct( + struct dcn20_link_encoder *enc20, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_aux_registers *aux_regs, + const struct dcn10_link_enc_hpd_registers *hpd_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask) +{ + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; + enum bp_result result = BP_RESULT_OK; + struct dcn10_link_encoder *enc10 = &enc20->enc10; + + enc10->base.funcs = &dcn31_link_enc_funcs; + enc10->base.ctx = init_data->ctx; + enc10->base.id = init_data->encoder; + + enc10->base.hpd_source = init_data->hpd_source; + enc10->base.connector = init_data->connector; + + enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; + + enc10->base.features = *enc_features; + + enc10->base.transmitter = init_data->transmitter; + + /* set the flag to indicate whether driver poll the I2C data pin + * while doing the DP sink detect + */ + +/* if (dal_adapter_service_is_feature_supported(as, + FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) + enc10->base.features.flags.bits. + DP_SINK_DETECT_POLL_DATA_PIN = true;*/ + + enc10->base.output_signals = + SIGNAL_TYPE_DVI_SINGLE_LINK | + SIGNAL_TYPE_DVI_DUAL_LINK | + SIGNAL_TYPE_LVDS | + SIGNAL_TYPE_DISPLAY_PORT | + SIGNAL_TYPE_DISPLAY_PORT_MST | + SIGNAL_TYPE_EDP | + SIGNAL_TYPE_HDMI_TYPE_A; + + /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. + * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. + * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer + * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. + * Prefer DIG assignment is decided by board design. + * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design + * and VBIOS will filter out 7 UNIPHY for DCE 8.0. + * By this, adding DIGG should not hurt DCE 8.0. + * This will let DCE 8.1 share DCE 8.0 as much as possible + */ + + enc10->link_regs = link_regs; + enc10->aux_regs = aux_regs; + enc10->hpd_regs = hpd_regs; + enc10->link_shift = link_shift; + enc10->link_mask = link_mask; + + switch (enc10->base.transmitter) { + case TRANSMITTER_UNIPHY_A: + enc10->base.preferred_engine = ENGINE_ID_DIGA; + break; + case TRANSMITTER_UNIPHY_B: + enc10->base.preferred_engine = ENGINE_ID_DIGB; + break; + case TRANSMITTER_UNIPHY_C: + enc10->base.preferred_engine = ENGINE_ID_DIGC; + break; + case TRANSMITTER_UNIPHY_D: + enc10->base.preferred_engine = ENGINE_ID_DIGD; + break; + case TRANSMITTER_UNIPHY_E: + enc10->base.preferred_engine = ENGINE_ID_DIGE; + break; + case TRANSMITTER_UNIPHY_F: + enc10->base.preferred_engine = ENGINE_ID_DIGF; + break; + default: + ASSERT_CRITICAL(false); + enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + + /* default to one to mirror Windows behavior */ + enc10->base.features.flags.bits.HDMI_6GB_EN = 1; + + result = bp_funcs->get_encoder_cap_info(enc10->base.ctx->dc_bios, + enc10->base.id, &bp_cap_info); + + /* Override features with DCE-specific values */ + if (result == BP_RESULT_OK) { + enc10->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc10->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; + enc10->base.features.flags.bits.DP_IS_USB_C = + bp_cap_info.DP_IS_USB_C; + } else { + DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + __func__, + result); + } + if (enc10->base.ctx->dc->debug.hdmi20_disable) { + enc10->base.features.flags.bits.HDMI_6GB_EN = 0; + } +} + +void dcn31_link_encoder_construct_minimal( + struct dcn20_link_encoder *enc20, + struct dc_context *ctx, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + enum engine_id eng_id) +{ + struct dcn10_link_encoder *enc10 = &enc20->enc10; + + enc10->base.funcs = &dcn31_link_enc_funcs; + enc10->base.ctx = ctx; + enc10->base.id.type = OBJECT_TYPE_ENCODER; + enc10->base.hpd_source = HPD_SOURCEID_UNKNOWN; + enc10->base.connector.type = OBJECT_TYPE_CONNECTOR; + enc10->base.preferred_engine = eng_id; + enc10->base.features = *enc_features; + enc10->base.transmitter = TRANSMITTER_UNKNOWN; + enc10->link_regs = link_regs; + + enc10->base.output_signals = + SIGNAL_TYPE_DISPLAY_PORT | + SIGNAL_TYPE_DISPLAY_PORT_MST | + SIGNAL_TYPE_EDP; +} + +void dcn31_link_encoder_enable_dp_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source) +{ + /* Enable transmitter and encoder. */ + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + + dcn20_link_encoder_enable_dp_output(enc, link_settings, clock_source); + + } else { + + /** @todo Handle transmitter with programmable mapping to link encoder. */ + } +} + +void dcn31_link_encoder_enable_dp_mst_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source) +{ + /* Enable transmitter and encoder. */ + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + + dcn10_link_encoder_enable_dp_mst_output(enc, link_settings, clock_source); + + } else { + + /** @todo Handle transmitter with programmable mapping to link encoder. */ + } +} + +void dcn31_link_encoder_disable_output( + struct link_encoder *enc, + enum signal_type signal) +{ + /* Disable transmitter and encoder. */ + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + + dcn10_link_encoder_disable_output(enc, signal); + + } else { + + /** @todo Handle transmitter with programmable mapping to link encoder. */ + } +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h new file mode 100644 index 000000000000..32d146312838 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h @@ -0,0 +1,246 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_LINK_ENCODER__DCN31_H__ +#define __DC_LINK_ENCODER__DCN31_H__ + +#include "dcn30/dcn30_dio_link_encoder.h" + + +#define LE_DCN31_REG_LIST(id)\ + LE_DCN3_REG_LIST(id),\ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \ + SR(DIO_LINKA_CNTL), \ + SR(DIO_LINKB_CNTL), \ + SR(DIO_LINKC_CNTL), \ + SR(DIO_LINKD_CNTL), \ + SR(DIO_LINKE_CNTL), \ + SR(DIO_LINKF_CNTL) + +#define LINK_ENCODER_MASK_SH_LIST_DCN31(mask_sh) \ + LINK_ENCODER_MASK_SH_LIST_DCN10(mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_EN, mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, mask_sh),\ + LE_SF(DIG0_TMDS_CTL_BITS, TMDS_CTL0, mask_sh), \ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_START_WINDOW, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_HALF_SYM_DETECT_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_TRANSITION_FILTER_EN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_PHASE_DETECT, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_START, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_STOP, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_PHASE_DETECT_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_DETECTION_THRESHOLD, mask_sh), \ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_TX_PRECHARGE_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_TX_PRECHARGE_SYMBOLS, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_MODE_DET_CHECK_DELAY, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL1, AUX_RX_PRECHARGE_SKIP, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN_MUL, mask_sh),\ + LE_SF(DIO_LINKA_CNTL, ENC_TYPE_SEL, mask_sh),\ + LE_SF(DIO_LINKA_CNTL, HPO_DP_ENC_SEL, mask_sh),\ + LE_SF(DIO_LINKA_CNTL, HPO_HDMI_ENC_SEL, mask_sh) + +#define DPCS_DCN31_REG_LIST(id) \ + SRI(TMDS_CTL_BITS, DIG, id), \ + SRI(RDPCSTX_PHY_CNTL3, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL4, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL5, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL6, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL7, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL8, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL9, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL10, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL11, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL12, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL13, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL14, RDPCSTX, id), \ + SRI(RDPCSTX_CNTL, RDPCSTX, id), \ + SRI(RDPCSTX_CLOCK_CNTL, RDPCSTX, id), \ + SRI(RDPCSTX_INTERRUPT_CONTROL, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL0, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_CNTL2, RDPCSTX, id), \ + SRI(RDPCS_TX_CR_ADDR, RDPCSTX, id), \ + SRI(RDPCS_TX_CR_DATA, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_FUSE0, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_FUSE1, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_FUSE2, RDPCSTX, id), \ + SRI(RDPCSTX_PHY_FUSE3, RDPCSTX, id), \ + SR(RDPCSTX0_RDPCSTX_SCRATCH), \ + SRI(RDPCSTX_PHY_RX_LD_VAL, RDPCSTX, id),\ + SRI(RDPCSTX_DMCU_DPALT_DIS_BLOCK_REG, RDPCSTX, id) + +#define DPCS_DCN31_MASK_SH_LIST(mask_sh)\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_CLK_RDY, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_CLK_RDY, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_CLK_RDY, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_CLK_RDY, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL4, RDPCS_PHY_DP_TX0_TERM_CTRL, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL4, RDPCS_PHY_DP_TX1_TERM_CTRL, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL4, RDPCS_PHY_DP_TX2_TERM_CTRL, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL4, RDPCS_PHY_DP_TX3_TERM_CTRL, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL11, RDPCS_PHY_DP_MPLLB_MULTIPLIER, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL5, RDPCS_PHY_DP_TX0_WIDTH, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL5, RDPCS_PHY_DP_TX0_RATE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL5, RDPCS_PHY_DP_TX1_WIDTH, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL5, RDPCS_PHY_DP_TX1_RATE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX2_PSTATE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX3_PSTATE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX2_MPLL_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX3_MPLL_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL7, RDPCS_PHY_DP_MPLLB_FRACN_QUOT, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL7, RDPCS_PHY_DP_MPLLB_FRACN_DEN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL8, RDPCS_PHY_DP_MPLLB_SSC_PEAK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL9, RDPCS_PHY_DP_MPLLB_SSC_UP_SPREAD, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL9, RDPCS_PHY_DP_MPLLB_SSC_STEPSIZE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL10, RDPCS_PHY_DP_MPLLB_FRACN_REM, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL11, RDPCS_PHY_DP_REF_CLK_MPLLB_DIV, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL11, RDPCS_PHY_HDMI_MPLLB_HDMI_DIV, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL12, RDPCS_PHY_DP_MPLLB_SSC_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL12, RDPCS_PHY_DP_MPLLB_DIV5_CLK_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL12, RDPCS_PHY_DP_MPLLB_TX_CLK_DIV, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL12, RDPCS_PHY_DP_MPLLB_WORD_DIV2_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL12, RDPCS_PHY_DP_MPLLB_STATE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL13, RDPCS_PHY_DP_MPLLB_DIV_CLK_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL13, RDPCS_PHY_DP_MPLLB_DIV_MULTIPLIER, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL14, RDPCS_PHY_DP_MPLLB_FRACN_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL14, RDPCS_PHY_DP_MPLLB_PMIX_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_LANE0_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_LANE1_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_LANE2_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_LANE3_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CNTL, RDPCS_TX_FIFO_RD_START_DELAY, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_EXT_REFCLK_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SRAMCLK_BYPASS, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SRAMCLK_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SRAMCLK_CLOCK_ON, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SYMCLK_DIV2_CLOCK_ON, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SYMCLK_DIV2_GATE_DIS, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_SYMCLK_DIV2_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_DISABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_DISABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_DISABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_DISABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_REQ, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_REQ, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_REQ, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_REQ, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_ACK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_ACK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_ACK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_ACK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_CR_MUX_SEL, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_REF_RANGE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_SRAM_BYPASS, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_SRAM_EXT_LD_DONE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_HDMIMODE_ENABLE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_SRAM_INIT_DONE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL2, RDPCS_PHY_DP4_POR, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_INTERRUPT_CONTROL, RDPCS_REG_FIFO_ERROR_MASK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_INTERRUPT_CONTROL, RDPCS_TX_FIFO_ERROR_MASK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_INTERRUPT_CONTROL, RDPCS_DPALT_DISABLE_TOGGLE_MASK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_INTERRUPT_CONTROL, RDPCS_DPALT_4LANE_TOGGLE_MASK, mask_sh),\ + LE_SF(RDPCSTX0_RDPCS_TX_CR_ADDR, RDPCS_TX_CR_ADDR, mask_sh),\ + LE_SF(RDPCSTX0_RDPCS_TX_CR_DATA, RDPCS_TX_CR_DATA, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE0, RDPCS_PHY_DP_MPLLB_V2I, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE0, RDPCS_PHY_DP_TX0_EQ_MAIN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE0, RDPCS_PHY_DP_TX0_EQ_PRE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE0, RDPCS_PHY_DP_TX0_EQ_POST, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE0, RDPCS_PHY_DP_MPLLB_FREQ_VCO, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE1, RDPCS_PHY_DP_MPLLB_CP_INT, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE1, RDPCS_PHY_DP_MPLLB_CP_PROP, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE1, RDPCS_PHY_DP_TX1_EQ_MAIN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE1, RDPCS_PHY_DP_TX1_EQ_PRE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE1, RDPCS_PHY_DP_TX1_EQ_POST, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE2, RDPCS_PHY_DP_TX2_EQ_MAIN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE2, RDPCS_PHY_DP_TX2_EQ_PRE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE2, RDPCS_PHY_DP_TX2_EQ_POST, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE3, RDPCS_PHY_DP_TX3_EQ_MAIN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE3, RDPCS_PHY_DCO_FINETUNE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE3, RDPCS_PHY_DCO_RANGE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE3, RDPCS_PHY_DP_TX3_EQ_PRE, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_FUSE3, RDPCS_PHY_DP_TX3_EQ_POST, mask_sh) + +void dcn31_link_encoder_construct( + struct dcn20_link_encoder *enc20, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_aux_registers *aux_regs, + const struct dcn10_link_enc_hpd_registers *hpd_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask); + +/* + * Create a minimal link encoder object with no dc_link object associated with it. + */ +void dcn31_link_encoder_construct_minimal( + struct dcn20_link_encoder *enc20, + struct dc_context *ctx, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + enum engine_id eng_id); + +void dcn31_link_encoder_set_dio_phy_mux( + struct link_encoder *enc, + enum encoder_type_select sel, + uint32_t hpo_inst); + +/* + * Enable DP transmitter and its encoder. + */ +void dcn31_link_encoder_enable_dp_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source); + +/* + * Enable DP transmitter and its encoder in MST mode. + */ +void dcn31_link_encoder_enable_dp_mst_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source); + +/* + * Disable transmitter and its encoder. + */ +void dcn31_link_encoder_disable_output( + struct link_encoder *enc, + enum signal_type signal); + +#endif /* __DC_LINK_ENCODER__DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c new file mode 100644 index 000000000000..bb9648488900 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -0,0 +1,956 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dcn30/dcn30_hubbub.h" +#include "dcn31_hubbub.h" +#include "dm_services.h" +#include "reg_helper.h" + + +#define CTX \ + hubbub2->base.ctx +#define DC_LOGGER \ + hubbub2->base.ctx->logger +#define REG(reg)\ + hubbub2->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hubbub2->shifts->field_name, hubbub2->masks->field_name + +#ifdef NUM_VMID +#undef NUM_VMID +#endif +#define NUM_VMID 16 + +#define DCN31_CRB_SEGMENT_SIZE_KB 64 + +static void dcn31_init_crb(struct hubbub *hubbub) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, + &hubbub2->det0_size); + + REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, + &hubbub2->det1_size); + + REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, + &hubbub2->det2_size); + + REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, + &hubbub2->det3_size); + + REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, + &hubbub2->compbuf_size_segments); + + REG_SET_2(COMPBUF_RESERVED_SPACE, 0, + COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32, + COMPBUF_RESERVED_SPACE_ZS, hubbub2->pixel_chunk_size / 128); + REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x17F); +} + +static void dcn31_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + unsigned int det_size_segments = (det_buffer_size_in_kbyte + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB; + + switch (hubp_inst) { + case 0: + REG_UPDATE(DCHUBBUB_DET0_CTRL, + DET0_SIZE, det_size_segments); + hubbub2->det0_size = det_size_segments; + break; + case 1: + REG_UPDATE(DCHUBBUB_DET1_CTRL, + DET1_SIZE, det_size_segments); + hubbub2->det1_size = det_size_segments; + break; + case 2: + REG_UPDATE(DCHUBBUB_DET2_CTRL, + DET2_SIZE, det_size_segments); + hubbub2->det2_size = det_size_segments; + break; + case 3: + REG_UPDATE(DCHUBBUB_DET3_CTRL, + DET3_SIZE, det_size_segments); + hubbub2->det3_size = det_size_segments; + break; + default: + break; + } + /* Should never be hit, if it is we have an erroneous hw config*/ + ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size + + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs); +} + +static void dcn31_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + unsigned int compbuf_size_segments = (compbuf_size_kb + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB; + + if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) { + if (compbuf_size_segments > hubbub2->compbuf_size_segments) { + REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); + REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); + REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); + REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); + } + /* Should never be hit, if it is we have an erroneous hw config*/ + ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size + + hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs); + REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments); + REG_WAIT(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, compbuf_size_segments, 1, 100); + hubbub2->compbuf_size_segments = compbuf_size_segments; + } +} + +static uint32_t convert_and_clamp( + uint32_t wm_ns, + uint32_t refclk_mhz, + uint32_t clamp_value) +{ + uint32_t ret_val = 0; + ret_val = wm_ns * refclk_mhz; + ret_val /= 1000; + + if (ret_val > clamp_value) + ret_val = clamp_value; + + return ret_val; +} + +static bool hubbub31_program_urgent_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t prog_wm_value; + bool wm_pending = false; + + /* Repeat for water mark set A, B, C and D. */ + /* clock state A */ + if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) { + hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + } else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns) + wm_pending = true; + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->a.frac_urg_bw_flip + > hubbub2->watermarks.a.frac_urg_bw_flip) { + hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip); + } else if (watermarks->a.frac_urg_bw_flip + < hubbub2->watermarks.a.frac_urg_bw_flip) + wm_pending = true; + + if (safe_to_lower || watermarks->a.frac_urg_bw_nom + > hubbub2->watermarks.a.frac_urg_bw_nom) { + hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom); + } else if (watermarks->a.frac_urg_bw_nom + < hubbub2->watermarks.a.frac_urg_bw_nom) + wm_pending = true; + + if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) { + hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0, + DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value); + } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns) + wm_pending = true; + + /* clock state B */ + if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) { + hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + } else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns) + wm_pending = true; + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->b.frac_urg_bw_flip + > hubbub2->watermarks.b.frac_urg_bw_flip) { + hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip); + } else if (watermarks->b.frac_urg_bw_flip + < hubbub2->watermarks.b.frac_urg_bw_flip) + wm_pending = true; + + if (safe_to_lower || watermarks->b.frac_urg_bw_nom + > hubbub2->watermarks.b.frac_urg_bw_nom) { + hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom); + } else if (watermarks->b.frac_urg_bw_nom + < hubbub2->watermarks.b.frac_urg_bw_nom) + wm_pending = true; + + if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) { + hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0, + DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value); + } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns) + wm_pending = true; + + /* clock state C */ + if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) { + hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + } else if (watermarks->c.urgent_ns < hubbub2->watermarks.c.urgent_ns) + wm_pending = true; + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->c.frac_urg_bw_flip + > hubbub2->watermarks.c.frac_urg_bw_flip) { + hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->c.frac_urg_bw_flip); + } else if (watermarks->c.frac_urg_bw_flip + < hubbub2->watermarks.c.frac_urg_bw_flip) + wm_pending = true; + + if (safe_to_lower || watermarks->c.frac_urg_bw_nom + > hubbub2->watermarks.c.frac_urg_bw_nom) { + hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->c.frac_urg_bw_nom); + } else if (watermarks->c.frac_urg_bw_nom + < hubbub2->watermarks.c.frac_urg_bw_nom) + wm_pending = true; + + if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) { + hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0, + DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value); + } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns) + wm_pending = true; + + /* clock state D */ + if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) { + hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + } else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns) + wm_pending = true; + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->d.frac_urg_bw_flip + > hubbub2->watermarks.d.frac_urg_bw_flip) { + hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip); + } else if (watermarks->d.frac_urg_bw_flip + < hubbub2->watermarks.d.frac_urg_bw_flip) + wm_pending = true; + + if (safe_to_lower || watermarks->d.frac_urg_bw_nom + > hubbub2->watermarks.d.frac_urg_bw_nom) { + hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom); + } else if (watermarks->d.frac_urg_bw_nom + < hubbub2->watermarks.d.frac_urg_bw_nom) + wm_pending = true; + + if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) { + hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0, + DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value); + } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns) + wm_pending = true; + + return wm_pending; +} + +static bool hubbub31_program_stutter_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t prog_wm_value; + bool wm_pending = false; + + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } else if (watermarks->a.cstate_pstate.cstate_exit_ns + < hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns + > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) { + hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); + } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns + < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_z8_ns + > hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) { + hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns = + watermarks->a.cstate_pstate.cstate_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); + } else if (watermarks->a.cstate_pstate.cstate_exit_z8_ns + < hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) + wm_pending = true; + + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } else if (watermarks->b.cstate_pstate.cstate_exit_ns + < hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns + > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) { + hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); + } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns + < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_z8_ns + > hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) { + hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns = + watermarks->b.cstate_pstate.cstate_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); + } else if (watermarks->b.cstate_pstate.cstate_exit_z8_ns + < hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) + wm_pending = true; + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } else if (watermarks->c.cstate_pstate.cstate_exit_ns + < hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns + > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) { + hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); + } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns + < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_z8_ns + > hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) { + hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns = + watermarks->c.cstate_pstate.cstate_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); + } else if (watermarks->c.cstate_pstate.cstate_exit_z8_ns + < hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) + wm_pending = true; + + /* clock state D */ + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } else if (watermarks->d.cstate_pstate.cstate_exit_ns + < hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns + > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) { + hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); + } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns + < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) + wm_pending = true; + + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_z8_ns + > hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) { + hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns = + watermarks->d.cstate_pstate.cstate_exit_z8_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_z8_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); + } else if (watermarks->d.cstate_pstate.cstate_exit_z8_ns + < hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) + wm_pending = true; + + return wm_pending; +} + +static bool hubbub31_program_pstate_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t prog_wm_value; + + bool wm_pending = false; + + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub2->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); + } else if (watermarks->a.cstate_pstate.pstate_change_ns + < hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) + wm_pending = true; + + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub2->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); + } else if (watermarks->b.cstate_pstate.pstate_change_ns + < hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) + wm_pending = false; + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub2->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); + } else if (watermarks->c.cstate_pstate.pstate_change_ns + < hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) + wm_pending = true; + + /* clock state D */ + if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns + > hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub2->watermarks.d.cstate_pstate.pstate_change_ns = + watermarks->d.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + } else if (watermarks->d.cstate_pstate.pstate_change_ns + < hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) + wm_pending = true; + + return wm_pending; +} + +static bool hubbub31_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + bool wm_pending = false; + + if (hubbub31_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) + wm_pending = true; + + if (hubbub31_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) + wm_pending = true; + + if (hubbub31_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) + wm_pending = true; + + /* + * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric. + * If the memory controller is fully utilized and the DCHub requestors are + * well ahead of their amortized schedule, then it is safe to prevent the next winner + * from being committed and sent to the fabric. + * The utilization of the memory controller is approximated by ensuring that + * the number of outstanding requests is greater than a threshold specified + * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule, + * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles. + * + * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF) + * to turn off it for now. + */ + /*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, + DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); + REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, + DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/ + + hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); + return wm_pending; +} + +static void hubbub3_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, + unsigned int bytes_per_element) +{ + /* copied from DML. might want to refactor DML to leverage from DML */ + /* DML : get_blk256_size */ + if (bytes_per_element == 1) { + *blk256_width = 16; + *blk256_height = 16; + } else if (bytes_per_element == 2) { + *blk256_width = 16; + *blk256_height = 8; + } else if (bytes_per_element == 4) { + *blk256_width = 8; + *blk256_height = 8; + } else if (bytes_per_element == 8) { + *blk256_width = 8; + *blk256_height = 4; + } +} + +static void hubbub31_det_request_size( + unsigned int detile_buf_size, + unsigned int height, + unsigned int width, + unsigned int bpe, + bool *req128_horz_wc, + bool *req128_vert_wc) +{ + unsigned int blk256_height = 0; + unsigned int blk256_width = 0; + unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; + + hubbub3_get_blk256_size(&blk256_width, &blk256_height, bpe); + + swath_bytes_horz_wc = width * blk256_height * bpe; + swath_bytes_vert_wc = height * blk256_width * bpe; + + *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ + + *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ +} + +static bool hubbub31_get_dcc_compression_cap(struct hubbub *hubbub, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + struct dc *dc = hubbub->ctx->dc; + enum dcc_control dcc_control; + unsigned int bpe; + enum segment_order segment_order_horz, segment_order_vert; + bool req128_horz_wc, req128_vert_wc; + + memset(output, 0, sizeof(*output)); + + if (dc->debug.disable_dcc == DCC_DISABLE) + return false; + + if (!hubbub->funcs->dcc_support_pixel_format(input->format, + &bpe)) + return false; + + if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, + &segment_order_horz, &segment_order_vert)) + return false; + + hubbub31_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size, + input->surface_size.height, input->surface_size.width, + bpe, &req128_horz_wc, &req128_vert_wc); + + if (!req128_horz_wc && !req128_vert_wc) { + dcc_control = dcc_control__256_256_xxx; + } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { + if (!req128_horz_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_horz == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else if (input->scan == SCAN_DIRECTION_VERTICAL) { + if (!req128_vert_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_vert == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else { + if ((req128_horz_wc && + segment_order_horz == segment_order__non_contiguous) || + (req128_vert_wc && + segment_order_vert == segment_order__non_contiguous)) + /* access_dir not known, must use most constraining */ + dcc_control = dcc_control__256_64_64; + else + /* reg128 is true for either horz and vert + * but segment_order is contiguous + */ + dcc_control = dcc_control__128_128_xxx; + } + + /* Exception for 64KB_R_X */ + if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X)) + dcc_control = dcc_control__128_128_xxx; + + if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && + dcc_control != dcc_control__256_256_xxx) + return false; + + switch (dcc_control) { + case dcc_control__256_256_xxx: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 256; + output->grph.rgb.independent_64b_blks = false; + output->grph.rgb.dcc_controls.dcc_256_256_unconstrained = 1; + output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; + break; + case dcc_control__128_128_xxx: + output->grph.rgb.max_uncompressed_blk_size = 128; + output->grph.rgb.max_compressed_blk_size = 128; + output->grph.rgb.independent_64b_blks = false; + output->grph.rgb.dcc_controls.dcc_128_128_uncontrained = 1; + output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; + break; + case dcc_control__256_64_64: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 64; + output->grph.rgb.independent_64b_blks = true; + output->grph.rgb.dcc_controls.dcc_256_64_64 = 1; + break; + case dcc_control__256_128_128: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 128; + output->grph.rgb.independent_64b_blks = false; + output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; + break; + } + output->capable = true; + output->const_color_support = true; + + return true; +} + +static int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config) +{ + hubbub3_init_dchub_sys_ctx(hubbub, pa_config); + + dcn21_dchvm_init(hubbub); + + return NUM_VMID; +} + +static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub, + unsigned int dccg_ref_freq_inKhz, + unsigned int *dchub_ref_freq_inKhz) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t ref_div = 0; + uint32_t ref_en = 0; + unsigned int dc_refclk_khz = 24000; + + REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div, + DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en); + + if (ref_en) { + if (ref_div == 2) + *dchub_ref_freq_inKhz = dc_refclk_khz / 2; + else + *dchub_ref_freq_inKhz = dc_refclk_khz; + + /* + * The external Reference Clock may change based on the board or + * platform requirements and the programmable integer divide must + * be programmed to provide a suitable DLG RefClk frequency between + * a minimum of 20MHz and maximum of 50MHz + */ + if (*dchub_ref_freq_inKhz < 20000 || *dchub_ref_freq_inKhz > 50000) + ASSERT_CRITICAL(false); + + return; + } else { + *dchub_ref_freq_inKhz = dc_refclk_khz; + + // HUBBUB global timer must be enabled. + ASSERT_CRITICAL(false); + return; + } +} + +static const struct hubbub_funcs hubbub31_funcs = { + .update_dchub = hubbub2_update_dchub, + .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx, + .init_vm_ctx = hubbub2_init_vm_ctx, + .dcc_support_swizzle = hubbub3_dcc_support_swizzle, + .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, + .get_dcc_compression_cap = hubbub31_get_dcc_compression_cap, + .wm_read_state = hubbub21_wm_read_state, + .get_dchub_ref_freq = hubbub31_get_dchub_ref_freq, + .program_watermarks = hubbub31_program_watermarks, + .allow_self_refresh_control = hubbub1_allow_self_refresh_control, + .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, + .program_det_size = dcn31_program_det_size, + .program_compbuf_size = dcn31_program_compbuf_size, + .init_crb = dcn31_init_crb +}; + +void hubbub31_construct(struct dcn20_hubbub *hubbub31, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask, + int det_size_kb, + int pixel_chunk_size_kb, + int config_return_buffer_size_kb) +{ + + hubbub3_construct(hubbub31, ctx, hubbub_regs, hubbub_shift, hubbub_mask); + hubbub31->base.funcs = &hubbub31_funcs; + hubbub31->detile_buf_size = det_size_kb * 1024; + hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024; + hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h new file mode 100644 index 000000000000..8ec98cbcbd47 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h @@ -0,0 +1,122 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HUBBUB_DCN31_H__ +#define __DC_HUBBUB_DCN31_H__ + +#include "dcn21/dcn21_hubbub.h" + +#define HUBBUB_REG_LIST_DCN31(id)\ + HUBBUB_REG_LIST_DCN30(id),\ + SR(DCHVM_CTRL0),\ + SR(DCHVM_MEM_CTRL),\ + SR(DCHVM_CLK_CTRL),\ + SR(DCHVM_RIOMMU_CTRL0),\ + SR(DCHVM_RIOMMU_STAT0),\ + SR(DCHUBBUB_DET0_CTRL),\ + SR(DCHUBBUB_DET1_CTRL),\ + SR(DCHUBBUB_DET2_CTRL),\ + SR(DCHUBBUB_DET3_CTRL),\ + SR(DCHUBBUB_COMPBUF_CTRL),\ + SR(COMPBUF_RESERVED_SPACE),\ + SR(DCHUBBUB_DEBUG_CTRL_0),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D) + +#define HUBBUB_MASK_SH_LIST_DCN31(mask_sh)\ + HUBBUB_MASK_SH_LIST_DCN_COMMON(mask_sh), \ + HUBBUB_MASK_SH_LIST_STUTTER(mask_sh), \ + HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_LOCATION_TOP, FB_TOP, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh), \ + HUBBUB_SF(DCHVM_CTRL0, HOSTVM_INIT_REQ, mask_sh),\ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, mask_sh),\ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_FORCE_REQ, mask_sh),\ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_POWER_STATUS, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_R_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_G_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_R_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_G_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, TR_REQ_REQCLKREQ_MODE, mask_sh),\ + HUBBUB_SF(DCHVM_CLK_CTRL, TW_RSP_COMPCLKREQ_MODE, mask_sh),\ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, mask_sh),\ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, mask_sh),\ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, mask_sh),\ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET0_CTRL, DET0_SIZE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET1_CTRL, DET1_SIZE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET2_CTRL, DET2_SIZE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET3_CTRL, DET3_SIZE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, mask_sh),\ + HUBBUB_SF(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, mask_sh),\ + HUBBUB_SF(COMPBUF_RESERVED_SPACE, COMPBUF_RESERVED_SPACE_64B, mask_sh),\ + HUBBUB_SF(COMPBUF_RESERVED_SPACE, COMPBUF_RESERVED_SPACE_ZS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, mask_sh) + + +void hubbub31_construct(struct dcn20_hubbub *hubbub3, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask, + int det_size_kb, + int pixel_chunk_size_kb, + int config_return_buffer_size_kb); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c new file mode 100644 index 000000000000..53b792b997b7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c @@ -0,0 +1,103 @@ +/* + * Copyright 2012-20 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dce_calcs.h" +#include "reg_helper.h" +#include "basics/conversion.h" +#include "dcn31_hubp.h" + +#define REG(reg)\ + hubp2->hubp_regs->reg + +#define CTX \ + hubp2->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubp2->hubp_shift->field_name, hubp2->hubp_mask->field_name + +void hubp31_set_unbounded_requesting(struct hubp *hubp, bool enable) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, enable); + REG_UPDATE(CURSOR_CONTROL, CURSOR_REQ_MODE, enable); +} + +void hubp31_soft_reset(struct hubp *hubp, bool reset) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_SOFT_RESET, reset); +} + +static struct hubp_funcs dcn31_hubp_funcs = { + .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, + .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, + .hubp_program_surface_flip_and_addr = hubp3_program_surface_flip_and_addr, + .hubp_program_surface_config = hubp3_program_surface_config, + .hubp_is_flip_pending = hubp2_is_flip_pending, + .hubp_setup = hubp3_setup, + .hubp_setup_interdependent = hubp2_setup_interdependent, + .hubp_set_vm_system_aperture_settings = hubp3_set_vm_system_aperture_settings, + .set_blank = hubp2_set_blank, + .dcc_control = hubp3_dcc_control, + .mem_program_viewport = min_set_viewport, + .set_cursor_attributes = hubp2_cursor_set_attributes, + .set_cursor_position = hubp2_cursor_set_position, + .hubp_clk_cntl = hubp2_clk_cntl, + .hubp_vtg_sel = hubp2_vtg_sel, + .dmdata_set_attributes = hubp3_dmdata_set_attributes, + .dmdata_load = hubp2_dmdata_load, + .dmdata_status_done = hubp2_dmdata_status_done, + .hubp_read_state = hubp3_read_state, + .hubp_clear_underflow = hubp2_clear_underflow, + .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, + .hubp_init = hubp3_init, + .set_unbounded_requesting = hubp31_set_unbounded_requesting, + .hubp_soft_reset = hubp31_soft_reset, + .hubp_in_blank = hubp1_in_blank, +}; + +bool hubp31_construct( + struct dcn20_hubp *hubp2, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_hubp2_registers *hubp_regs, + const struct dcn_hubp2_shift *hubp_shift, + const struct dcn_hubp2_mask *hubp_mask) +{ + hubp2->base.funcs = &dcn31_hubp_funcs; + hubp2->base.ctx = ctx; + hubp2->hubp_regs = hubp_regs; + hubp2->hubp_shift = hubp_shift; + hubp2->hubp_mask = hubp_mask; + hubp2->base.inst = inst; + hubp2->base.opp_id = OPP_ID_INVALID; + hubp2->base.mpcc_id = 0xf; + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.h new file mode 100644 index 000000000000..c31a7b8f81ee --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.h @@ -0,0 +1,246 @@ +/* + * Copyright 2012-20 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HUBP_DCN31_H__ +#define __DC_HUBP_DCN31_H__ + +#include "dcn20/dcn20_hubp.h" +#include "dcn21/dcn21_hubp.h" +#include "dcn30/dcn30_hubp.h" + +#define HUBP_MASK_SH_LIST_DCN31(mask_sh)\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, REFCYC_PER_VM_DMDATA, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_FAULT_STATUS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_FAULT_STATUS_CLEAR, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_UNDERFLOW_STATUS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_LATE_STATUS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_UNDERFLOW_STATUS_CLEAR, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_DONE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_IN_BLANK, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_SOFT_RESET, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, MAX_COMPRESSED_FRAGS, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PKRS, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, SW_MODE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, META_LINEAR, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, PIPE_ALIGNED, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, META_PITCH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, PITCH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, META_PITCH_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_TYPE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_PENDING, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_UPDATE_LOCK, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_X_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_Y_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_WIDTH, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_X_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_Y_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_WIDTH_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_HEIGHT_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_X_START_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_Y_START_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION_C, SEC_VIEWPORT_WIDTH_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION_C, SEC_VIEWPORT_HEIGHT_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START_C, SEC_VIEWPORT_X_START_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START_C, SEC_VIEWPORT_Y_START_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, PRIMARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS, PRIMARY_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, SECONDARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS, SECONDARY_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, PRIMARY_META_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS, PRIMARY_META_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, SECONDARY_META_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS, SECONDARY_META_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, PRIMARY_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_C, PRIMARY_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, SECONDARY_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_C, SECONDARY_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, PRIMARY_META_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, PRIMARY_META_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH_C, SECONDARY_META_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS_C, SECONDARY_META_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE, SURFACE_INUSE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH, SURFACE_INUSE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_C, SURFACE_INUSE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH_C, SURFACE_INUSE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE, SURFACE_EARLIEST_INUSE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_C, SURFACE_EARLIEST_INUSE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_BLK, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_BLK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_IND_BLK, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_IND_BLK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_Y_G, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_ALPHA, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, PACK_3TO2_ELEMENT_DISABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, DRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, PRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, MRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, CRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MIN_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, META_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MIN_META_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, DPTE_GROUP_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, SWATH_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, PTE_ROW_HEIGHT_LINEAR, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MIN_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, META_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MIN_META_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, DPTE_GROUP_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, SWATH_HEIGHT_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, PTE_ROW_HEIGHT_LINEAR_C, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, REFCYC_H_BLANK_END, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, DLG_V_BLANK_END, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_1, MIN_DST_Y_NEXT_START, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_DIMENSIONS, REFCYC_PER_HTOTAL, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, REFCYC_X_AFTER_SCALER, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, DST_Y_AFTER_SCALER, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_VM_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_ROW_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_REF_FREQ_TO_PIX_FREQ, REF_FREQ_TO_PIX_FREQ, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_1, REFCYC_PER_PTE_GROUP_VBLANK_L, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_3, REFCYC_PER_META_CHUNK_VBLANK_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_4, DST_Y_PER_META_ROW_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_5, REFCYC_PER_META_CHUNK_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_C, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_2, REFCYC_PER_PTE_GROUP_VBLANK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_4, REFCYC_PER_META_CHUNK_VBLANK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_6, DST_Y_PER_META_ROW_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_7, REFCYC_PER_META_CHUNK_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_TTU_QOS_WM, QoS_LEVEL_LOW_WM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_TTU_QOS_WM, QoS_LEVEL_HIGH_WM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, MIN_TTU_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, QoS_LEVEL_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, ROW_TTU_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, REFCYC_PER_REQ_DELIVERY, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_LEVEL_FIXED, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_RAMP_DISABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL1, REFCYC_PER_REQ_DELIVERY_PRE, mask_sh),\ + HUBP_SF(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, mask_sh),\ + HUBP_MASK_SH_LIST_DCN_VM(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ALPHA_PLANE_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, DST_Y_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, VRATIO_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS_C, VRATIO_PREFETCH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR, MC_VM_SYSTEM_APERTURE_LOW_ADDR, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, MC_VM_SYSTEM_APERTURE_HIGH_ADDR, mask_sh),\ + HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \ + HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_REQ_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_ADDRESS_HIGH, DMDATA_ADDRESS_HIGH, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_UPDATED, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_REPEAT, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_SIZE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_UPDATED, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_REPEAT, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_SIZE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_QOS_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_QOS_LEVEL, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_DL_DELTA, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_STATUS, DMDATA_DONE, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_VM_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_ROW_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_1, REFCYC_PER_PTE_GROUP_FLIP_L, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_2, REFCYC_PER_META_CHUNK_FLIP_L, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE_STOP_DATA_DURING_VM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, HUBPREQ_MASTER_UPDATE_LOCK_STATUS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_VMID_SETTINGS_0, VMID, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_3, REFCYC_PER_VM_GROUP_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_4, REFCYC_PER_VM_REQ_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_5, REFCYC_PER_PTE_GROUP_FLIP_C, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_6, REFCYC_PER_META_CHUNK_FLIP_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_5, REFCYC_PER_VM_GROUP_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_6, REFCYC_PER_VM_REQ_VBLANK, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, VM_GROUP_SIZE, mask_sh) + + +bool hubp31_construct( + struct dcn20_hubp *hubp2, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_hubp2_registers *hubp_regs, + const struct dcn_hubp2_shift *hubp_shift, + const struct dcn_hubp2_mask *hubp_mask); + +void hubp31_soft_reset(struct hubp *hubp, bool reset); + +void hubp31_set_unbounded_requesting(struct hubp *hubp, bool enable); + +#endif /* __DC_HUBP_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c new file mode 100644 index 000000000000..fc1fc1a4bf8b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -0,0 +1,596 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "reg_helper.h" +#include "abm.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "dcn31_hwseq.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dce/dmub_outbox.h" +#include "dc_link_dp.h" +#include "inc/link_dpcd.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + dc->ctx->logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +void dcn31_init_hw(struct dc *dc) +{ + struct abm **abms = dc->res_pool->multiple_abms; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + int i, j; + int edp_num; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + + REG_WRITE(REFCLK_CNTL, 0); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + //Enable ability to power gate / don't force power on permanently + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(hws, true); + + return; + } + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + hws->funcs.bios_golden_init(dc); + hws->funcs.disable_vga(dc->hwseq); + } + + if (dc->debug.enable_mem_low_power.bits.dmcu) { + // Force ERAM to shutdown if DMCU is not enabled + if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { + REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); + } + } + + // Set default OPTC memory power states + if (dc->debug.enable_mem_low_power.bits.optc) { + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.vga) { + // Power down VGA memory + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); + } + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) + link->link_status.link_active = true; + } + + /* Power gate DSCs */ + for (i = 0; i < res_pool->res_cap->num_dsc; i++) + if (hws->funcs.dsc_pg_control != NULL) + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); + + /* we want to turn off all dp displays before doing detection */ + if (dc->config.power_down_display_on_boot) { + uint8_t dpcd_power_state = '\0'; + enum dc_status status = DC_ERROR_UNEXPECTED; + + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) + continue; + + /* if any of the displays are lit up turn them off */ + status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) { + /* blank dp stream before power off receiver*/ + if (dc->links[i]->link_enc->funcs->get_dig_frontend) { + unsigned int fe; + + fe = dc->links[i]->link_enc->funcs->get_dig_frontend( + dc->links[i]->link_enc); + if (fe == ENGINE_ID_UNKNOWN) + continue; + + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { + if (fe == dc->res_pool->stream_enc[j]->id) { + dc->res_pool->stream_enc[j]->funcs->dp_blank( + dc->res_pool->stream_enc[j]); + break; + } + } + } + dp_receiver_power_ctrl(dc->links[i], false); + } + } + } + + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } + + /* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on and seamless boot not enabled + */ + if (dc->config.power_down_display_on_boot) { + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *edp_link; + + get_edp_links(dc, edp_links, &edp_num); + if (edp_num) { + for (i = 0; i < edp_num; i++) { + edp_link = edp_links[i]; + if (edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwss.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwss.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } + } + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (abms[i] != NULL) + abms[i]->funcs->abm_init(abms[i], backlight); + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + if (dc->clk_mgr->funcs->set_hard_max_memclk) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); +} + +void dcn31_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + + +void dcn31_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = true; /* disable power gating */ + + if (enable) + force_on = false; + + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + /* DCS0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); +} + +void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) +{ + bool is_hdmi_tmds; + bool is_dp; + + ASSERT(pipe_ctx->stream); + + if (pipe_ctx->stream_res.stream_enc == NULL) + return; /* this is not root pipe */ + + is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); + is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); + + if (!is_hdmi_tmds) + return; + + if (is_hdmi_tmds) + pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + else { + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + } +} + +void dcn31_z10_restore(struct dc *dc) +{ + union dmub_rb_cmd cmd; + + /* + * DMUB notifies whether restore is required. + * Optimization to avoid sending commands when not required. + */ + if (!dc_dmub_srv_is_restore_required(dc->ctx->dmub_srv)) + return; + + memset(&cmd, 0, sizeof(cmd)); + cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; + cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_RESTORE; + + dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); + dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); +} + +void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: + REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 1: + REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 2: + REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 3: + REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +{ + struct dcn_hubbub_phys_addr_config config; + + config.system_aperture.fb_top = pa_config->system_aperture.fb_top; + config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; + config.system_aperture.fb_base = pa_config->system_aperture.fb_base; + config.system_aperture.agp_top = pa_config->system_aperture.agp_top; + config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; + config.system_aperture.agp_base = pa_config->system_aperture.agp_base; + config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; + config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; + + if (pa_config->gart_config.base_addr_is_mc_addr) { + /* Convert from MC address to offset into FB */ + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr - + pa_config->system_aperture.fb_base + + pa_config->system_aperture.fb_offset; + } else + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + + return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); +} + +static void dcn31_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dc_link *link; + + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + ASSERT(!pipe_ctx->top_pipe); + + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + link = pipe_ctx->stream->link; + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } + } + } else if (pipe_ctx->stream_res.dsc) { + dp_set_dsc_enable(pipe_ctx, false); + } + + pipe_ctx->stream = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +void dcn31_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + dcn31_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} + +bool dcn31_is_abm_supported(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream) +{ + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == stream && + (pipe_ctx->prev_odm_pipe == NULL && pipe_ctx->next_odm_pipe == NULL)) + return true; + } + return false; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h new file mode 100644 index 000000000000..ff72f0fdd5be --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h @@ -0,0 +1,56 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN31_H__ +#define __DC_HWSS_DCN31_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +void dcn31_init_hw(struct dc *dc); + +void dcn31_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + +void dcn31_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); + +void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx); + +void dcn31_z10_restore(struct dc *dc); + +void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); +int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config); +void dcn31_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +bool dcn31_is_abm_supported(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream); + +#endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c new file mode 100644 index 000000000000..e3048f8827d2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -0,0 +1,150 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hw_sequencer.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" +#include "dcn31/dcn31_hwseq.h" + +static const struct hw_sequencer_funcs dcn31_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn31_init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn31_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .apply_idle_power_optimizations = dcn30_apply_idle_power_optimizations, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .z10_restore = dcn31_z10_restore, + .is_abm_supported = dcn31_is_abm_supported, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .update_visual_confirm_color = dcn20_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn31_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn30_set_input_transfer_func, + .set_output_transfer_func = dcn30_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn31_enable_power_gating_plane, + .hubp_pg_control = dcn31_hubp_pg_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn31_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn30_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn31_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn31_funcs; + dc->hwseq->funcs = dcn31_private_funcs; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwseq->funcs.init_pipes = NULL; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h new file mode 100644 index 000000000000..a3db08c8bd35 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_DCN31_INIT_H__ +#define __DC_DCN31_INIT_H__ + +struct dc; + +void dcn31_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN31_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c new file mode 100644 index 000000000000..a4b1d98f0007 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c @@ -0,0 +1,287 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dcn31_optc.h" + +#include "dcn30/dcn30_optc.h" +#include "reg_helper.h" +#include "dc.h" +#include "dcn_calc_math.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; + uint32_t memory_mask = 0; + int mem_count_per_opp = (mpcc_hactive + 2559) / 2560; + + /* Assume less than 6 pipes */ + if (opp_cnt == 4) { + if (mem_count_per_opp == 1) + memory_mask = 0xf; + else { + ASSERT(mem_count_per_opp == 2); + memory_mask = 0xff; + } + } else if (mem_count_per_opp == 1) + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); + else if (mem_count_per_opp == 2) + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + else if (mem_count_per_opp == 3) + memory_mask = 0x77; + else if (mem_count_per_opp == 4) + memory_mask = 0xff; + + if (REG(OPTC_MEMORY_CONFIG)) + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +/** + * Enable CRTC + * Enable CRTC - call ASIC Control Object to enable Timing generator. + */ +static bool optc31_enable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 2, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc - call ASIC Control Object to disable Timing generator. */ +static bool optc31_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + return true; +} + +static bool optc31_immediate_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 0, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + return true; +} + +static void optc31_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + + optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); + + /* + * MIN_MASK_EN is gone and MASK is now always enabled. + * + * To get it to it work with manual trigger we need to make sure + * we program the correct bit. + */ + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + + } else { + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_SET_V_TOTAL_MIN_MASK, 0, + OTG_V_TOTAL_MIN_SEL, 0, + OTG_V_TOTAL_MAX_SEL, 0, + OTG_FORCE_LOCK_ON_EVENT, 0); + + optc->funcs->set_vtotal_min_max(optc, 0, 0); + } +} + +static struct timing_generator_funcs dcn31_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc31_enable_crtc, + .disable_crtc = optc31_disable_crtc, + .immediate_disable_crtc = optc31_immediate_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .is_locked = optc1_is_locked, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc31_set_drr, + .set_vtotal_min_max = optc1_set_vtotal_min_max, + .set_static_screen_control = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .tg_init = optc3_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .set_dwb_source = NULL, + .set_odm_bypass = optc3_set_odm_bypass, + .set_odm_combine = optc31_set_odm_combine, + .get_optc_source = optc2_get_optc_source, + .set_out_mux = optc3_set_out_mux, + .set_drr_trigger_window = optc3_set_drr_trigger_window, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, +}; + +void dcn31_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn31_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h new file mode 100644 index 000000000000..d8ef2f0d0c95 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h @@ -0,0 +1,259 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_OPTC_DCN31_H__ +#define __DC_OPTC_DCN31_H__ + +#include "dcn10/dcn10_optc.h" + +#define OPTC_COMMON_REG_LIST_DCN3_1(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_M_CONST_DTO0, OTG, inst),\ + SRI(OTG_M_CONST_DTO1, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ + SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ + SR(DWB_SOURCE_SELECT) + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_END_X, mask_sh),\ + SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\ + SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh) + +void dcn31_timing_generator_init(struct optc *optc1); + +#endif /* __DC_OPTC_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c new file mode 100644 index 000000000000..7db268da6976 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c @@ -0,0 +1,157 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "reg_helper.h" +#include "core_types.h" +#include "dc_dmub_srv.h" +#include "dcn31_panel_cntl.h" +#include "atom.h" + +#define TO_DCN31_PANEL_CNTL(panel_cntl)\ + container_of(panel_cntl, struct dcn31_panel_cntl, base) + +#define CTX \ + dcn31_panel_cntl->base.ctx + +#define DC_LOGGER \ + dcn31_panel_cntl->base.ctx->logger + +static bool dcn31_query_backlight_info(struct panel_cntl *panel_cntl, union dmub_rb_cmd *cmd) +{ + struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(panel_cntl); + struct dc_dmub_srv *dc_dmub_srv = panel_cntl->ctx->dmub_srv; + + if (!dc_dmub_srv) + return false; + + memset(cmd, 0, sizeof(*cmd)); + cmd->panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; + cmd->panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO; + cmd->panel_cntl.header.payload_bytes = sizeof(cmd->panel_cntl.data); + cmd->panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + + return dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, cmd); +} + +static uint32_t dcn31_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl) +{ + union dmub_rb_cmd cmd; + + if (!dcn31_query_backlight_info(panel_cntl, &cmd)) + return 0; + + return cmd.panel_cntl.data.current_backlight; +} + +uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl) +{ + struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(panel_cntl); + struct dc_dmub_srv *dc_dmub_srv = panel_cntl->ctx->dmub_srv; + union dmub_rb_cmd cmd; + + if (!dc_dmub_srv) + return 0; + + memset(&cmd, 0, sizeof(cmd)); + cmd.panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; + cmd.panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_HW_INIT; + cmd.panel_cntl.header.payload_bytes = sizeof(cmd.panel_cntl.data); + cmd.panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + cmd.panel_cntl.data.bl_pwm_cntl = panel_cntl->stored_backlight_registers.BL_PWM_CNTL; + cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL; + cmd.panel_cntl.data.bl_pwm_ref_div1 = + panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV; + + if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd)) + return 0; + + panel_cntl->stored_backlight_registers.BL_PWM_CNTL = cmd.panel_cntl.data.bl_pwm_cntl; + panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 = 0; /* unused */ + panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL = cmd.panel_cntl.data.bl_pwm_period_cntl; + panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = + cmd.panel_cntl.data.bl_pwm_ref_div1; + + return cmd.panel_cntl.data.current_backlight; +} + +void dcn31_panel_cntl_destroy(struct panel_cntl **panel_cntl) +{ + struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(*panel_cntl); + + kfree(dcn31_panel_cntl); + *panel_cntl = NULL; +} + +bool dcn31_is_panel_backlight_on(struct panel_cntl *panel_cntl) +{ + union dmub_rb_cmd cmd; + + if (!dcn31_query_backlight_info(panel_cntl, &cmd)) + return 0; + + return cmd.panel_cntl.data.is_backlight_on; +} + +bool dcn31_is_panel_powered_on(struct panel_cntl *panel_cntl) +{ + union dmub_rb_cmd cmd; + + if (!dcn31_query_backlight_info(panel_cntl, &cmd)) + return 0; + + return cmd.panel_cntl.data.is_powered_on; +} + +void dcn31_store_backlight_level(struct panel_cntl *panel_cntl) +{ + union dmub_rb_cmd cmd; + + if (!dcn31_query_backlight_info(panel_cntl, &cmd)) + return; + + panel_cntl->stored_backlight_registers.BL_PWM_CNTL = cmd.panel_cntl.data.bl_pwm_cntl; + panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 = 0; /* unused */ + panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL = cmd.panel_cntl.data.bl_pwm_period_cntl; + panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = + cmd.panel_cntl.data.bl_pwm_ref_div1; +} + +static const struct panel_cntl_funcs dcn31_link_panel_cntl_funcs = { + .destroy = dcn31_panel_cntl_destroy, + .hw_init = dcn31_panel_cntl_hw_init, + .is_panel_backlight_on = dcn31_is_panel_backlight_on, + .is_panel_powered_on = dcn31_is_panel_powered_on, + .store_backlight_level = dcn31_store_backlight_level, + .get_current_backlight = dcn31_get_16_bit_backlight_from_pwm, +}; + +void dcn31_panel_cntl_construct( + struct dcn31_panel_cntl *dcn31_panel_cntl, + const struct panel_cntl_init_data *init_data) +{ + dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs; + dcn31_panel_cntl->base.ctx = init_data->ctx; + dcn31_panel_cntl->base.inst = init_data->inst; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.h new file mode 100644 index 000000000000..d33ccd6ef8c3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_PANEL_CNTL__DCN31_H__ +#define __DC_PANEL_CNTL__DCN31_H__ + +#include "panel_cntl.h" +#include "dce/dce_panel_cntl.h" + +struct dcn31_panel_cntl { + struct panel_cntl base; +}; + +void dcn31_panel_cntl_construct( + struct dcn31_panel_cntl *dcn31_panel_cntl, + const struct panel_cntl_init_data *init_data); + +#endif /* __DC_PANEL_CNTL__DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c new file mode 100644 index 000000000000..c67bc9544f5d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -0,0 +1,2195 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dc.h" + +#include "dcn31/dcn31_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn31_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn31/dcn31_hubp.h" +#include "irq/dcn31/irq_service_dcn31.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn31/dcn31_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn31/dcn31_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +// TODO: change include headers /amd/include/asic_reg after upstream +#include "yellow_carp_offset.h" +#include "dcn/dcn_3_1_2_offset.h" +#include "dcn/dcn_3_1_2_sh_mask.h" +#include "nbio/nbio_7_2_0_offset.h" +#include "dpcs/dpcs_4_2_0_offset.h" +#include "dpcs/dpcs_4_2_0_sh_mask.h" +#include "mmhub/mmhub_2_3_0_offset.h" +#include "mmhub/mmhub_2_3_0_sh_mask.h" + + +#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 +#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "link_enc_cfg.h" + +#define DC_LOGGER_INIT(logger) +#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) +#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) + +#define DCN3_1_DEFAULT_DET_SIZE 384 + +struct _vcs_dpi_ip_params_st dcn3_1_ip = { + .gpuvm_enable = 1, + .gpuvm_max_page_table_levels = 1, + .hostvm_enable = 1, + .hostvm_max_page_table_levels = 2, + .rob_buffer_size_kbytes = 64, + .det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE, + .config_return_buffer_size_in_kbytes = 1792, + .compressed_buffer_segment_size_in_kbytes = 64, + .meta_fifo_size_in_kentries = 32, + .zero_size_buffer_entries = 512, + .compbuf_reserved_space_64b = 256, + .compbuf_reserved_space_zs = 64, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .meta_chunk_size_kbytes = 2, + .min_meta_chunk_size_bytes = 256, + .writeback_chunk_size_kbytes = 8, + .ptoi_supported = false, + .num_dsc = 3, + .maximum_dsc_bits_per_component = 10, + .dsc422_native_support = false, + .is_line_buffer_bpp_fixed = true, + .line_buffer_fixed_bpp = 48, + .line_buffer_size_bits = 789504, + .max_line_buffer_lines = 12, + .writeback_interface_buffer_size_kbytes = 90, + .max_num_dpp = 4, + .max_num_otg = 4, + .max_num_hdmi_frl_outputs = 1, + .max_num_wb = 1, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 6, + .max_vscl_ratio = 6, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dpte_buffer_size_in_pte_reqs_luma = 64, + .dpte_buffer_size_in_pte_reqs_chroma = 34, + .dispclk_ramp_margin_percent = 1, + .max_inter_dcn_tile_repeaters = 8, + .cursor_buffer_size = 16, + .cursor_chunk_size = 2, + .writeback_line_buffer_buffer_size = 0, + .writeback_min_hscl_ratio = 1, + .writeback_min_vscl_ratio = 1, + .writeback_max_hscl_ratio = 1, + .writeback_max_vscl_ratio = 1, + .writeback_max_hscl_taps = 1, + .writeback_max_vscl_taps = 1, + .dppclk_delay_subtotal = 46, + .dppclk_delay_scl = 50, + .dppclk_delay_scl_lb_only = 16, + .dppclk_delay_cnvc_formatter = 27, + .dppclk_delay_cnvc_cursor = 6, + .dispclk_delay_subtotal = 119, + .dynamic_metadata_vm_enabled = false, + .odm_combine_4to1_supported = false, + .dcc_supported = true, +}; + +struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = { + /*TODO: correct dispclk/dppclk voltage level determination*/ + .clock_limits = { + { + .state = 0, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 600.0, + .phyclk_d18_mhz = 667.0, + .dscclk_mhz = 186.0, + .dtbclk_mhz = 625.0, + }, + { + .state = 1, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .phyclk_d18_mhz = 667.0, + .dscclk_mhz = 209.0, + .dtbclk_mhz = 625.0, + }, + { + .state = 2, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .phyclk_d18_mhz = 667.0, + .dscclk_mhz = 209.0, + .dtbclk_mhz = 625.0, + }, + { + .state = 3, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .phyclk_d18_mhz = 667.0, + .dscclk_mhz = 371.0, + .dtbclk_mhz = 625.0, + }, + { + .state = 4, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .phyclk_d18_mhz = 667.0, + .dscclk_mhz = 417.0, + .dtbclk_mhz = 625.0, + }, + }, + .num_states = 5, + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .sr_exit_z8_time_us = 402.0, + .sr_enter_plus_exit_z8_time_us = 520.0, + .writeback_latency_us = 12.0, + .round_trip_ping_latency_dcfclk_cycles = 106, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, + .pct_ideal_sdp_bw_after_urgent = 80.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0, + .max_avg_sdp_bw_use_normal_percent = 60.0, + .max_avg_dram_bw_use_normal_percent = 60.0, + .fabric_datapath_to_dcn_data_return_bytes = 32, + .return_bus_width_bytes = 64, + .downspread_percent = 0.38, + .dcn_downspread_percent = 0.5, + .gpuvm_min_page_size_bytes = 4096, + .hostvm_min_page_size_bytes = 4096, + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, +}; + +enum dcn31_clk_src_array_id { + DCN31_CLK_SRC_PLL0, + DCN31_CLK_SRC_PLL1, + DCN31_CLK_SRC_PLL2, + DCN31_CLK_SRC_PLL3, + DCN31_CLK_SRC_PLL4, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +/* TODO awful hack. fixup dcn20_dwb.h */ +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* CLOCK */ +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + +#define CLK_BASE(seg) \ + CLK_BASE_INNER(seg) + +#define CLK_SRI(reg_name, block, inst)\ + .reg_name = CLK_BASE(reg ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## _ ## inst ## _ ## reg_name + + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN301_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), + vpg_regs(7), + vpg_regs(8), + vpg_regs(9), +}; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN31_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN31_REG_LIST(id), \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ + DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ + DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + //MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN31(_MASK) +}; +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN31(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN31(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN31() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN31(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN31_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING) + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN31_REG_LIST() +}; + +#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN31_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn31 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .blends_with_above = true, + .blends_with_below = true, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = false, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_AVOID, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = false, + .i2c = false, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = false, + .cm = false, + .mpc = false, + .optc = false, + } + }, + .optimize_edp_link_rate = true, + .enable_sw_cntl_psr = true, +}; + +static const struct dc_debug_options debug_defaults_diags = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = true, + .clock_trace = true, + .disable_dpp_power_gate = true, + .disable_hubp_power_gate = true, + .disable_clock_gate = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true, + .disable_stutter = false, + .scl_reset_length10 = true, + .dwb_fi_phase = -1, // -1 = disable + .dmub_command_table = true, + .enable_tri_buf = true, + .use_max_lb = true +}; + +static void dcn31_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn31_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn31_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn31_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub31_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + dcn3_1_ip.det_buffer_size_kbytes, + dcn3_1_ip.pixel_chunk_size_kbytes, + dcn3_1_ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn31.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn31_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn31_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn31_link_encoder_create( + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn31_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + + vpg3_construct(vpg3, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg3->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + + afmt3_construct(afmt3, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + return &afmt3->base; +} + +static struct stream_encoder *dcn31_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) + return NULL; + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct dce_hwseq *dcn31_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn31_stream_encoder_create, + .create_hwseq = dcn31_hwseq_create, +}; + +static const struct resource_create_funcs res_create_maximus_funcs = { + .read_dce_straps = NULL, + .create_audio = NULL, + .create_stream_encoder = NULL, + .create_hwseq = dcn31_hwseq_create, +}; + +static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn31_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn31_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp31_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn31_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static void dcn31_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn31_resource_pool *dcn31_pool = TO_DCN31_RES_POOL(*pool); + + dcn31_resource_destruct(dcn31_pool); + kfree(dcn31_pool); + *pool = NULL; +} + +static struct clock_source *dcn31_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + +static int dcn31_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe; + + dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_crtc_timing *timing; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + pipes[pipe_cnt].pipe.src.gpuvm = true; + pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; + pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; + pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.src.dcc_rate = 3; + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + + if (pipes[pipe_cnt].dout.dsc_enable) { + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + pipes[pipe_cnt].dout.dsc_input_bpc = 8; + break; + case COLOR_DEPTH_101010: + pipes[pipe_cnt].dout.dsc_input_bpc = 10; + break; + case COLOR_DEPTH_121212: + pipes[pipe_cnt].dout.dsc_input_bpc = 12; + break; + default: + ASSERT(0); + break; + } + } + + pipe_cnt++; + } + context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE; + dc->config.enable_4to1MPC = false; + if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { + if (is_dual_plane(pipe->plane_state->format) + && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) { + dc->config.enable_4to1MPC = true; + } else if (!is_dual_plane(pipe->plane_state->format)) { + context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; + pipes[0].pipe.src.unbounded_req_mode = true; + } + } + + return pipe_cnt; +} + +static void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) +{ + if (dc->clk_mgr->bw_params->wm_table.entries[WM_A].valid) { + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.entries[WM_A].pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.entries[WM_A].sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.entries[WM_A].sr_exit_time_us; + } +} + +static void dcn31_calculate_wm_and_dlg_fp( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + int i, pipe_idx; + double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; + + if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk) + dcfclk = context->bw_ctx.dml.soc.min_dcfclk; + + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = dcfclk; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz; + +#if 0 // TODO + /* Set B: + * TODO + */ + if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) { + if (vlevel == 0) { + pipes[0].clks_cfg.voltage = 1; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz; + } + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us; + } + context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = dcfclk; + + /* Set C: + * TODO + */ + if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) { + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us; + } + context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + + /* Set D: + * TODO + */ + if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) { + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us; + } + context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; +#endif + + /* Set A: + * All clocks min required + * + * Set A calculated last so that following calculations are based on Set A + */ + dc->res_pool->funcs->update_soc_for_wm_a(dc, context); + context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + /* TODO: remove: */ + context->bw_ctx.bw.dcn.watermarks.b = context->bw_ctx.bw.dcn.watermarks.a; + context->bw_ctx.bw.dcn.watermarks.c = context->bw_ctx.bw.dcn.watermarks.a; + context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a; + /* end remove*/ + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); + pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + + if (dc->config.forced_clocks) { + pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; + pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; + } + if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) + pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; + if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) + pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; + + pipe_idx++; + } + + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); +} + +static void dcn31_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + DC_FP_START(); + dcn31_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + struct clk_limit_table *clk_table = &bw_params->clk_table; + struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; + unsigned int i, closest_clk_lvl; + int j; + + // Default clock levels are used for diags, which may lead to overclocking. + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { + int max_dispclk_mhz = 0, max_dppclk_mhz = 0; + + dcn3_1_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator; + dcn3_1_ip.max_num_dpp = dc->res_pool->pipe_count; + dcn3_1_soc.num_chans = bw_params->num_channels; + + ASSERT(clk_table->num_entries); + + /* Prepass to find max clocks independent of voltage level. */ + for (i = 0; i < clk_table->num_entries; ++i) { + if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz) + max_dispclk_mhz = clk_table->entries[i].dispclk_mhz; + if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz) + max_dppclk_mhz = clk_table->entries[i].dppclk_mhz; + } + + for (i = 0; i < clk_table->num_entries; i++) { + /* loop backwards*/ + for (closest_clk_lvl = 0, j = dcn3_1_soc.num_states - 1; j >= 0; j--) { + if ((unsigned int) dcn3_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) { + closest_clk_lvl = j; + break; + } + } + + clock_limits[i].state = i; + + /* Clocks dependent on voltage level. */ + clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; + clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; + clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; + clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio; + + /* Clocks independent of voltage level. */ + clock_limits[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz : + dcn3_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz; + + clock_limits[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz : + dcn3_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz; + + clock_limits[i].dram_bw_per_chan_gbps = dcn3_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; + clock_limits[i].dscclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz; + clock_limits[i].dtbclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; + clock_limits[i].phyclk_d18_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; + clock_limits[i].phyclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz; + } + for (i = 0; i < clk_table->num_entries; i++) + dcn3_1_soc.clock_limits[i] = clock_limits[i]; + if (clk_table->num_entries) { + dcn3_1_soc.num_states = clk_table->num_entries; + } + } + + dcn3_1_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31); + else + dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31_FPGA); +} + +static struct resource_funcs dcn31_res_pool_funcs = { + .destroy = dcn31_destroy_resource_pool, + .link_enc_create = dcn31_link_encoder_create, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .link_encs_assign = link_enc_cfg_link_encs_assign, + .link_enc_unassign = link_enc_cfg_link_enc_unassign, + .panel_cntl_create = dcn31_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, + .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, + .populate_dml_pipes = dcn31_populate_dml_pipes_from_context, + .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, + .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut, + .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, + .update_bw_bounding_box = dcn31_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, +}; + +static struct clock_source *dcn30_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dcn31_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn31_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + DC_FP_START(); + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn31; + + pool->base.funcs = &dcn31_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; + dc->caps.max_downscale_ratio = 600; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.4 w/a applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + + dc->caps.max_slave_planes = 1; + dc->caps.max_slave_yuv_planes = 1; + dc->caps.max_slave_rgb_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) { + dc->debug = debug_defaults_diags; + } else + dc->debug = debug_defaults_diags; + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* TODO: DCCG */ + pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* TODO: IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn31_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn31_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn31_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn31_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn31_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn31_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn31_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn31_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn31_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ? + &res_create_funcs : &res_create_maximus_funcs))) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn31_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + DC_FP_END(); + + return true; + +create_fail: + + DC_FP_END(); + dcn31_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn31_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn31_resource_pool *pool = + kzalloc(sizeof(struct dcn31_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn31_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h new file mode 100644 index 000000000000..93571c976996 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DCN31_RESOURCE_H_ +#define _DCN31_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN31_RES_POOL(pool)\ + container_of(pool, struct dcn31_resource_pool, base) + +struct dcn31_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn31_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN31_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h index cac0b2c0d31b..a9170b9f84d3 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h +++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h @@ -32,6 +32,9 @@ struct cp_psp_stream_config { uint8_t otg_inst; uint8_t dig_be; uint8_t dig_fe; + uint8_t link_enc_idx; + uint8_t stream_enc_idx; + uint8_t phy_idx; uint8_t assr_enabled; uint8_t mst_enabled; void *dm_stream_ctx; diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 304d50d16d01..9ab854293ace 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -162,6 +162,12 @@ void dm_set_dcn_clocks( bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable); +void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us); + +// 0x1 = Result_OK, 0xFE = Result_UnkmownCmd +#define IS_SMU_TIMEOUT(result) \ + (!(result == 0x1 || result == 0xFE)) + int dm_helper_dmub_aux_transfer_sync( struct dc_context *ctx, const struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index fb41140e8381..4440d08743aa 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -245,6 +245,8 @@ struct pp_smu_funcs_nv { #define PP_SMU_NUM_DCFCLK_DPM_LEVELS 8 #define PP_SMU_NUM_FCLK_DPM_LEVELS 4 #define PP_SMU_NUM_MEMCLK_DPM_LEVELS 4 +#define PP_SMU_NUM_DCLK_DPM_LEVELS 8 +#define PP_SMU_NUM_VCLK_DPM_LEVELS 8 struct dpm_clock { uint32_t Freq; // In MHz @@ -258,6 +260,8 @@ struct dpm_clocks { struct dpm_clock SocClocks[PP_SMU_NUM_SOCCLK_DPM_LEVELS]; struct dpm_clock FClocks[PP_SMU_NUM_FCLK_DPM_LEVELS]; struct dpm_clock MemClocks[PP_SMU_NUM_MEMCLK_DPM_LEVELS]; + struct dpm_clock VClocks[PP_SMU_NUM_VCLK_DPM_LEVELS]; + struct dpm_clock DClocks[PP_SMU_NUM_DCLK_DPM_LEVELS]; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 6bb7f2905821..d34024fd798a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -62,6 +62,8 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) -Wframe-larger-than=2048 CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) -Wframe-larger-than=2048 +CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_rcflags) @@ -72,6 +74,8 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags) endif CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags) @@ -86,6 +90,7 @@ DML += display_mode_vba.o dcn20/display_rq_dlg_calc_20.o dcn20/display_mode_vba_ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o +DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o endif AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index ec56210b6180..9d2016d8fafe 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -64,6 +64,7 @@ typedef struct { #define BPP_INVALID 0 #define BPP_BLENDED_PIPE 0xffffffff #define DCN30_MAX_DSC_IMAGE_WIDTH 5184 +#define DCN30_MAX_FMT_420_BUFFER_WIDTH 4096 static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib); static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( @@ -2052,7 +2053,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->DISPCLKWithoutRamping, v->DISPCLKDPPCLKVCOSpeed); v->MaxDispclkRoundedToDFSGranularity = RoundToDFSGranularityDown( - v->soc.clock_limits[mode_lib->soc.num_states].dispclk_mhz, + v->soc.clock_limits[mode_lib->soc.num_states - 1].dispclk_mhz, v->DISPCLKDPPCLKVCOSpeed); if (v->DISPCLKWithoutRampingRoundedToDFSGranularity > v->MaxDispclkRoundedToDFSGranularity) { @@ -3957,20 +3958,20 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { v->PlaneRequiredDISPCLKWithoutODMCombine = v->PixelClock[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * (1.0 + v->DISPCLKRampingMargin / 100.0); - if ((v->PlaneRequiredDISPCLKWithoutODMCombine >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states] - && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states])) { + if ((v->PlaneRequiredDISPCLKWithoutODMCombine >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states - 1])) { v->PlaneRequiredDISPCLKWithoutODMCombine = v->PixelClock[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); } v->PlaneRequiredDISPCLKWithODMCombine2To1 = v->PixelClock[k] / 2 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * (1 + v->DISPCLKRampingMargin / 100.0); - if ((v->PlaneRequiredDISPCLKWithODMCombine2To1 >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states] - && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states])) { + if ((v->PlaneRequiredDISPCLKWithODMCombine2To1 >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states - 1])) { v->PlaneRequiredDISPCLKWithODMCombine2To1 = v->PixelClock[k] / 2 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); } v->PlaneRequiredDISPCLKWithODMCombine4To1 = v->PixelClock[k] / 4 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * (1 + v->DISPCLKRampingMargin / 100.0); - if ((v->PlaneRequiredDISPCLKWithODMCombine4To1 >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states] - && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states])) { + if ((v->PlaneRequiredDISPCLKWithODMCombine4To1 >= v->MaxDispclk[i] && v->MaxDispclk[i] == v->MaxDispclk[mode_lib->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[mode_lib->soc.num_states - 1])) { v->PlaneRequiredDISPCLKWithODMCombine4To1 = v->PixelClock[k] / 4 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); } @@ -3987,19 +3988,30 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } else if (v->PlaneRequiredDISPCLKWithoutODMCombine > v->MaxDispclkRoundedDownToDFSGranularity) { v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; - } else if (v->DSCEnabled[k] && (v->HActive[k] > DCN30_MAX_DSC_IMAGE_WIDTH)) { - v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; - v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; } else { v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled; v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithoutODMCombine; - /*420 format workaround*/ - if (v->HActive[k] > 4096 && v->OutputFormat[k] == dm_420) { + } + if (v->DSCEnabled[k] && v->HActive[k] > DCN30_MAX_DSC_IMAGE_WIDTH + && v->ODMCombineEnablePerState[i][k] != dm_odm_combine_mode_4to1) { + if (v->HActive[k] / 2 > DCN30_MAX_DSC_IMAGE_WIDTH) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_4to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine4To1; + } else { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; + } + } + if (v->OutputFormat[k] == dm_420 && v->HActive[k] > DCN30_MAX_FMT_420_BUFFER_WIDTH + && v->ODMCombineEnablePerState[i][k] != dm_odm_combine_mode_4to1) { + if (v->HActive[k] / 2 > DCN30_MAX_FMT_420_BUFFER_WIDTH) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_4to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine4To1; + } else { v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; } } - if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1) { v->MPCCombine[i][j][k] = false; v->NoOfDPP[i][j][k] = 4; @@ -4281,42 +4293,8 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } } - for (i = 0; i < v->soc.num_states; i++) { - v->DSCCLKRequiredMoreThanSupported[i] = false; - for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { - if (v->BlendingAndTiming[k] == k) { - if (v->Output[k] == dm_dp || v->Output[k] == dm_edp) { - if (v->OutputFormat[k] == dm_420) { - v->DSCFormatFactor = 2; - } else if (v->OutputFormat[k] == dm_444) { - v->DSCFormatFactor = 1; - } else if (v->OutputFormat[k] == dm_n422) { - v->DSCFormatFactor = 2; - } else { - v->DSCFormatFactor = 1; - } - if (v->RequiresDSC[i][k] == true) { - if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1) { - if (v->PixelClockBackEnd[k] / 12.0 / v->DSCFormatFactor - > (1.0 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * v->MaxDSCCLK[i]) { - v->DSCCLKRequiredMoreThanSupported[i] = true; - } - } else if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_2to1) { - if (v->PixelClockBackEnd[k] / 6.0 / v->DSCFormatFactor - > (1.0 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * v->MaxDSCCLK[i]) { - v->DSCCLKRequiredMoreThanSupported[i] = true; - } - } else { - if (v->PixelClockBackEnd[k] / 3.0 / v->DSCFormatFactor - > (1.0 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * v->MaxDSCCLK[i]) { - v->DSCCLKRequiredMoreThanSupported[i] = true; - } - } - } - } - } - } - } + /* Skip dscclk validation: as long as dispclk is supported, dscclk is also implicitly supported */ + for (i = 0; i < v->soc.num_states; i++) { v->NotEnoughDSCUnits[i] = false; v->TotalDSCUnitsRequired = 0.0; @@ -5319,7 +5297,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l for (j = 0; j < 2; j++) { if (v->ScaleRatioAndTapsSupport == 1 && v->SourceFormatPixelAndScanSupport == 1 && v->ViewportSizeSupport[i][j] == 1 && v->DIOSupport[i] == 1 && v->ODMCombine4To1SupportCheckOK[i] == 1 - && v->NotEnoughDSCUnits[i] == 0 && v->DSCCLKRequiredMoreThanSupported[i] == 0 + && v->NotEnoughDSCUnits[i] == 0 && v->DTBCLKRequiredMoreThanSupported[i] == 0 && v->ROBSupport[i][j] == 1 && v->DISPCLK_DPPCLK_Support[i][j] == 1 && v->TotalAvailablePipesSupport[i][j] == 1 && EnoughWritebackUnits == 1 && WritebackModeSupport == 1 diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c new file mode 100644 index 000000000000..a9667068c690 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -0,0 +1,7510 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dc.h" +#include "dc_link.h" +#include "../display_mode_lib.h" +#include "display_mode_vba_31.h" +#include "../dml_inline_defs.h" + +/* + * NOTE: + * This file is gcc-parsable HW gospel, coming straight from HW engineers. + * + * It doesn't adhere to Linux kernel style and sometimes will do things in odd + * ways. Unless there is something clearly wrong with it the code should + * remain as-is as it provides us with a guarantee from HW that it is correct. + */ + +#define BPP_INVALID 0 +#define BPP_BLENDED_PIPE 0xffffffff +#define DCN31_MAX_DSC_IMAGE_WIDTH 5184 +#define DCN31_MAX_FMT_420_BUFFER_WIDTH 4096 + +// For DML-C changes that hasn't been propagated to VBA yet +//#define __DML_VBA_ALLOW_DELTA__ + +// Move these to ip paramaters/constant + +// At which vstartup the DML start to try if the mode can be supported +#define __DML_VBA_MIN_VSTARTUP__ 9 + +// Delay in DCFCLK from ARB to DET (1st num is ARB to SDPIF, 2nd number is SDPIF to DET) +#define __DML_ARB_TO_RET_DELAY__ (7 + 95) + +// fudge factor for min dcfclk calclation +#define __DML_MIN_DCFCLK_FACTOR__ 1.15 + +typedef struct { + double DPPCLK; + double DISPCLK; + double PixelClock; + double DCFCLKDeepSleep; + unsigned int DPPPerPlane; + bool ScalerEnabled; + enum scan_direction_class SourceScan; + unsigned int BlockWidth256BytesY; + unsigned int BlockHeight256BytesY; + unsigned int BlockWidth256BytesC; + unsigned int BlockHeight256BytesC; + unsigned int InterlaceEnable; + unsigned int NumberOfCursors; + unsigned int VBlank; + unsigned int HTotal; + unsigned int DCCEnable; + bool ODMCombineIsEnabled; + enum source_format_class SourcePixelFormat; + int BytePerPixelY; + int BytePerPixelC; + bool ProgressiveToInterlaceUnitInOPP; +} Pipe; + +#define BPP_INVALID 0 +#define BPP_BLENDED_PIPE 0xffffffff + +static bool CalculateBytePerPixelAnd256BBlockSizes( + enum source_format_class SourcePixelFormat, + enum dm_swizzle_mode SurfaceTiling, + unsigned int *BytePerPixelY, + unsigned int *BytePerPixelC, + double *BytePerPixelDETY, + double *BytePerPixelDETC, + unsigned int *BlockHeight256BytesY, + unsigned int *BlockHeight256BytesC, + unsigned int *BlockWidth256BytesY, + unsigned int *BlockWidth256BytesC); +static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib); +static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(struct display_mode_lib *mode_lib); +static unsigned int dscceComputeDelay( + unsigned int bpc, + double BPP, + unsigned int sliceWidth, + unsigned int numSlices, + enum output_format_class pixelFormat, + enum output_encoder_class Output); +static unsigned int dscComputeDelay(enum output_format_class pixelFormat, enum output_encoder_class Output); +static bool CalculatePrefetchSchedule( + struct display_mode_lib *mode_lib, + double HostVMInefficiencyFactor, + Pipe *myPipe, + unsigned int DSCDelay, + double DPPCLKDelaySubtotalPlusCNVCFormater, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int DPP_RECOUT_WIDTH, + enum output_format_class OutputFormat, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int MaxVStartup, + unsigned int GPUVMPageTableLevels, + bool GPUVMEnable, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + double HostVMMinPageSize, + bool DynamicMetadataEnable, + bool DynamicMetadataVMEnabled, + int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + double UrgentLatency, + double UrgentExtraLatency, + double TCalc, + unsigned int PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + double PrefetchSourceLinesY, + unsigned int SwathWidthY, + double VInitPreFillY, + unsigned int MaxNumSwathY, + double PrefetchSourceLinesC, + unsigned int SwathWidthC, + double VInitPreFillC, + unsigned int MaxNumSwathC, + int swath_width_luma_ub, + int swath_width_chroma_ub, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double TWait, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBWLuma, + double *RequiredPrefetchPixDataBWChroma, + bool *NotEnoughTimeForDynamicMetadata, + double *Tno_bw, + double *prefetch_vmrow_bw, + double *Tdmdl_vm, + double *Tdmdl, + double *TSetup, + int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix); +static double RoundToDFSGranularityUp(double Clock, double VCOSpeed); +static double RoundToDFSGranularityDown(double Clock, double VCOSpeed); +static void CalculateDCCConfiguration( + bool DCCEnabled, + bool DCCProgrammingAssumesScanDirectionUnknown, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceWidthLuma, + unsigned int SurfaceWidthChroma, + unsigned int SurfaceHeightLuma, + unsigned int SurfaceHeightChroma, + double DETBufferSize, + unsigned int RequestHeight256ByteLuma, + unsigned int RequestHeight256ByteChroma, + enum dm_swizzle_mode TilingFormat, + unsigned int BytePerPixelY, + unsigned int BytePerPixelC, + double BytePerPixelDETY, + double BytePerPixelDETC, + enum scan_direction_class ScanOrientation, + unsigned int *MaxUncompressedBlockLuma, + unsigned int *MaxUncompressedBlockChroma, + unsigned int *MaxCompressedBlockLuma, + unsigned int *MaxCompressedBlockChroma, + unsigned int *IndependentBlockLuma, + unsigned int *IndependentBlockChroma); +static double CalculatePrefetchSourceLines( + struct display_mode_lib *mode_lib, + double VRatio, + double vtaps, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + unsigned int SwathHeight, + unsigned int ViewportYStart, + double *VInitPreFill, + unsigned int *MaxNumSwath); +static unsigned int CalculateVMAndRowBytes( + struct display_mode_lib *mode_lib, + bool DCCEnable, + unsigned int BlockHeight256Bytes, + unsigned int BlockWidth256Bytes, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceTiling, + unsigned int BytePerPixel, + enum scan_direction_class ScanDirection, + unsigned int SwathWidth, + unsigned int ViewportHeight, + bool GPUVMEnable, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + unsigned int GPUVMMinPageSize, + unsigned int HostVMMinPageSize, + unsigned int PTEBufferSizeInRequests, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + int *dpte_row_width_ub, + unsigned int *dpte_row_height, + unsigned int *MetaRequestWidth, + unsigned int *MetaRequestHeight, + unsigned int *meta_row_width, + unsigned int *meta_row_height, + int *vm_group_bytes, + unsigned int *dpte_group_bytes, + unsigned int *PixelPTEReqWidth, + unsigned int *PixelPTEReqHeight, + unsigned int *PTERequestSize, + int *DPDE0BytesFrame, + int *MetaPTEBytesFrame); +static double CalculateTWait(unsigned int PrefetchMode, double DRAMClockChangeLatency, double UrgentLatency, double SREnterPlusExitTime); +static void CalculateRowBandwidth( + bool GPUVMEnable, + enum source_format_class SourcePixelFormat, + double VRatio, + double VRatioChroma, + bool DCCEnable, + double LineTime, + unsigned int MetaRowByteLuma, + unsigned int MetaRowByteChroma, + unsigned int meta_row_height_luma, + unsigned int meta_row_height_chroma, + unsigned int PixelPTEBytesPerRowLuma, + unsigned int PixelPTEBytesPerRowChroma, + unsigned int dpte_row_height_luma, + unsigned int dpte_row_height_chroma, + double *meta_row_bw, + double *dpte_row_bw); + +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double HostVMInefficiencyFactor, + double UrgentExtraLatency, + double UrgentLatency, + unsigned int GPUVMMaxPageTableLevels, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + bool GPUVMEnable, + double HostVMMinPageSize, + double PDEAndMetaPTEBytesPerFrame, + double MetaRowBytes, + double DPTEBytesPerRow, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + double LineTime, + double VRatio, + double VRatioChroma, + double Tno_bw, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + unsigned int dpte_row_height_chroma, + unsigned int meta_row_height_chroma, + double *DestinationLinesToRequestVMInImmediateFlip, + double *DestinationLinesToRequestRowInImmediateFlip, + double *final_flip_bw, + bool *ImmediateFlipSupportedForPipe); +static double CalculateWriteBackDelay( + enum source_format_class WritebackPixelFormat, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackVTaps, + int WritebackDestinationWidth, + int WritebackDestinationHeight, + int WritebackSourceHeight, + unsigned int HTotal); + +static void CalculateVupdateAndDynamicMetadataParameters( + int MaxInterDCNTileRepeaters, + double DPPCLK, + double DISPCLK, + double DCFClkDeepSleep, + double PixelClock, + int HTotal, + int VBlank, + int DynamicMetadataTransmittedBytes, + int DynamicMetadataLinesBeforeActiveRequired, + int InterlaceEnable, + bool ProgressiveToInterlaceUnitInOPP, + double *TSetup, + double *Tdmbf, + double *Tdmec, + double *Tdmsks, + int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix); + +static void CalculateWatermarksAndDRAMSpeedChangeSupport( + struct display_mode_lib *mode_lib, + unsigned int PrefetchMode, + unsigned int NumberOfActivePlanes, + unsigned int MaxLineBufferLines, + unsigned int LineBufferSize, + unsigned int WritebackInterfaceBufferSize, + double DCFCLK, + double ReturnBW, + bool SynchronizedVBlank, + unsigned int dpte_group_bytes[], + unsigned int MetaChunkSize, + double UrgentLatency, + double ExtraLatency, + double WritebackLatency, + double WritebackChunkSize, + double SOCCLK, + double DRAMClockChangeLatency, + double SRExitTime, + double SREnterPlusExitTime, + double SRExitZ8Time, + double SREnterPlusExitZ8Time, + double DCFCLKDeepSleep, + unsigned int DETBufferSizeY[], + unsigned int DETBufferSizeC[], + unsigned int SwathHeightY[], + unsigned int SwathHeightC[], + unsigned int LBBitPerPixel[], + double SwathWidthY[], + double SwathWidthC[], + double HRatio[], + double HRatioChroma[], + unsigned int vtaps[], + unsigned int VTAPsChroma[], + double VRatio[], + double VRatioChroma[], + unsigned int HTotal[], + double PixelClock[], + unsigned int BlendingAndTiming[], + unsigned int DPPPerPlane[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + double DSTXAfterScaler[], + double DSTYAfterScaler[], + bool WritebackEnable[], + enum source_format_class WritebackPixelFormat[], + double WritebackDestinationWidth[], + double WritebackDestinationHeight[], + double WritebackSourceHeight[], + bool UnboundedRequestEnabled, + int unsigned CompressedBufferSizeInkByte, + enum clock_change_support *DRAMClockChangeSupport, + double *UrgentWatermark, + double *WritebackUrgentWatermark, + double *DRAMClockChangeWatermark, + double *WritebackDRAMClockChangeWatermark, + double *StutterExitWatermark, + double *StutterEnterPlusExitWatermark, + double *Z8StutterExitWatermark, + double *Z8StutterEnterPlusExitWatermark, + double *MinActiveDRAMClockChangeLatencySupported); + +static void CalculateDCFCLKDeepSleep( + struct display_mode_lib *mode_lib, + unsigned int NumberOfActivePlanes, + int BytePerPixelY[], + int BytePerPixelC[], + double VRatio[], + double VRatioChroma[], + double SwathWidthY[], + double SwathWidthC[], + unsigned int DPPPerPlane[], + double HRatio[], + double HRatioChroma[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double ReadBandwidthLuma[], + double ReadBandwidthChroma[], + int ReturnBusWidth, + double *DCFCLKDeepSleep); + +static void CalculateUrgentBurstFactor( + int swath_width_luma_ub, + int swath_width_chroma_ub, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double LineTime, + double UrgentLatency, + double CursorBufferSize, + unsigned int CursorWidth, + unsigned int CursorBPP, + double VRatio, + double VRatioC, + double BytePerPixelInDETY, + double BytePerPixelInDETC, + double DETBufferSizeY, + double DETBufferSizeC, + double *UrgentBurstFactorCursor, + double *UrgentBurstFactorLuma, + double *UrgentBurstFactorChroma, + bool *NotEnoughUrgentLatencyHiding); + +static void UseMinimumDCFCLK( + struct display_mode_lib *mode_lib, + int MaxInterDCNTileRepeaters, + int MaxPrefetchMode, + double FinalDRAMClockChangeLatency, + double SREnterPlusExitTime, + int ReturnBusWidth, + int RoundTripPingLatencyCycles, + int ReorderingBytes, + int PixelChunkSizeInKByte, + int MetaChunkSize, + bool GPUVMEnable, + int GPUVMMaxPageTableLevels, + bool HostVMEnable, + int NumberOfActivePlanes, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels, + bool DynamicMetadataVMEnabled, + enum immediate_flip_requirement ImmediateFlipRequirement, + bool ProgressiveToInterlaceUnitInOPP, + double MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation, + double PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency, + int VTotal[], + int VActive[], + int DynamicMetadataTransmittedBytes[], + int DynamicMetadataLinesBeforeActiveRequired[], + bool Interlace[], + double RequiredDPPCLK[][2][DC__NUM_DPP__MAX], + double RequiredDISPCLK[][2], + double UrgLatency[], + unsigned int NoOfDPP[][2][DC__NUM_DPP__MAX], + double ProjectedDCFCLKDeepSleep[][2], + double MaximumVStartup[][2][DC__NUM_DPP__MAX], + double TotalVActivePixelBandwidth[][2], + double TotalVActiveCursorBandwidth[][2], + double TotalMetaRowBandwidth[][2], + double TotalDPTERowBandwidth[][2], + unsigned int TotalNumberOfActiveDPP[][2], + unsigned int TotalNumberOfDCCActiveDPP[][2], + int dpte_group_bytes[], + double PrefetchLinesY[][2][DC__NUM_DPP__MAX], + double PrefetchLinesC[][2][DC__NUM_DPP__MAX], + int swath_width_luma_ub_all_states[][2][DC__NUM_DPP__MAX], + int swath_width_chroma_ub_all_states[][2][DC__NUM_DPP__MAX], + int BytePerPixelY[], + int BytePerPixelC[], + int HTotal[], + double PixelClock[], + double PDEAndMetaPTEBytesPerFrame[][2][DC__NUM_DPP__MAX], + double DPTEBytesPerRow[][2][DC__NUM_DPP__MAX], + double MetaRowBytes[][2][DC__NUM_DPP__MAX], + bool DynamicMetadataEnable[], + double VActivePixelBandwidth[][2][DC__NUM_DPP__MAX], + double VActiveCursorBandwidth[][2][DC__NUM_DPP__MAX], + double ReadBandwidthLuma[], + double ReadBandwidthChroma[], + double DCFCLKPerState[], + double DCFCLKState[][2]); + +static void CalculatePixelDeliveryTimes( + unsigned int NumberOfActivePlanes, + double VRatio[], + double VRatioChroma[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + unsigned int swath_width_luma_ub[], + unsigned int swath_width_chroma_ub[], + unsigned int DPPPerPlane[], + double HRatio[], + double HRatioChroma[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + int BytePerPixelC[], + enum scan_direction_class SourceScan[], + unsigned int NumberOfCursors[], + unsigned int CursorWidth[][DC__NUM_CURSOR__MAX], + unsigned int CursorBPP[][DC__NUM_CURSOR__MAX], + unsigned int BlockWidth256BytesY[], + unsigned int BlockHeight256BytesY[], + unsigned int BlockWidth256BytesC[], + unsigned int BlockHeight256BytesC[], + double DisplayPipeLineDeliveryTimeLuma[], + double DisplayPipeLineDeliveryTimeChroma[], + double DisplayPipeLineDeliveryTimeLumaPrefetch[], + double DisplayPipeLineDeliveryTimeChromaPrefetch[], + double DisplayPipeRequestDeliveryTimeLuma[], + double DisplayPipeRequestDeliveryTimeChroma[], + double DisplayPipeRequestDeliveryTimeLumaPrefetch[], + double DisplayPipeRequestDeliveryTimeChromaPrefetch[], + double CursorRequestDeliveryTime[], + double CursorRequestDeliveryTimePrefetch[]); + +static void CalculateMetaAndPTETimes( + int NumberOfActivePlanes, + bool GPUVMEnable, + int MetaChunkSize, + int MinMetaChunkSizeBytes, + int HTotal[], + double VRatio[], + double VRatioChroma[], + double DestinationLinesToRequestRowInVBlank[], + double DestinationLinesToRequestRowInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + int BytePerPixelY[], + int BytePerPixelC[], + enum scan_direction_class SourceScan[], + int dpte_row_height[], + int dpte_row_height_chroma[], + int meta_row_width[], + int meta_row_width_chroma[], + int meta_row_height[], + int meta_row_height_chroma[], + int meta_req_width[], + int meta_req_width_chroma[], + int meta_req_height[], + int meta_req_height_chroma[], + int dpte_group_bytes[], + int PTERequestSizeY[], + int PTERequestSizeC[], + int PixelPTEReqWidthY[], + int PixelPTEReqHeightY[], + int PixelPTEReqWidthC[], + int PixelPTEReqHeightC[], + int dpte_row_width_luma_ub[], + int dpte_row_width_chroma_ub[], + double DST_Y_PER_PTE_ROW_NOM_L[], + double DST_Y_PER_PTE_ROW_NOM_C[], + double DST_Y_PER_META_ROW_NOM_L[], + double DST_Y_PER_META_ROW_NOM_C[], + double TimePerMetaChunkNominal[], + double TimePerChromaMetaChunkNominal[], + double TimePerMetaChunkVBlank[], + double TimePerChromaMetaChunkVBlank[], + double TimePerMetaChunkFlip[], + double TimePerChromaMetaChunkFlip[], + double time_per_pte_group_nom_luma[], + double time_per_pte_group_vblank_luma[], + double time_per_pte_group_flip_luma[], + double time_per_pte_group_nom_chroma[], + double time_per_pte_group_vblank_chroma[], + double time_per_pte_group_flip_chroma[]); + +static void CalculateVMGroupAndRequestTimes( + unsigned int NumberOfActivePlanes, + bool GPUVMEnable, + unsigned int GPUVMMaxPageTableLevels, + unsigned int HTotal[], + int BytePerPixelC[], + double DestinationLinesToRequestVMInVBlank[], + double DestinationLinesToRequestVMInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + int dpte_row_width_luma_ub[], + int dpte_row_width_chroma_ub[], + int vm_group_bytes[], + unsigned int dpde0_bytes_per_frame_ub_l[], + unsigned int dpde0_bytes_per_frame_ub_c[], + int meta_pte_bytes_per_frame_ub_l[], + int meta_pte_bytes_per_frame_ub_c[], + double TimePerVMGroupVBlank[], + double TimePerVMGroupFlip[], + double TimePerVMRequestVBlank[], + double TimePerVMRequestFlip[]); + +static void CalculateStutterEfficiency( + struct display_mode_lib *mode_lib, + int CompressedBufferSizeInkByte, + bool UnboundedRequestEnabled, + int ConfigReturnBufferSizeInKByte, + int MetaFIFOSizeInKEntries, + int ZeroSizeBufferEntries, + int NumberOfActivePlanes, + int ROBBufferSizeInKByte, + double TotalDataReadBandwidth, + double DCFCLK, + double ReturnBW, + double COMPBUF_RESERVED_SPACE_64B, + double COMPBUF_RESERVED_SPACE_ZS, + double SRExitTime, + double SRExitZ8Time, + bool SynchronizedVBlank, + double Z8StutterEnterPlusExitWatermark, + double StutterEnterPlusExitWatermark, + bool ProgressiveToInterlaceUnitInOPP, + bool Interlace[], + double MinTTUVBlank[], + int DPPPerPlane[], + unsigned int DETBufferSizeY[], + int BytePerPixelY[], + double BytePerPixelDETY[], + double SwathWidthY[], + int SwathHeightY[], + int SwathHeightC[], + double NetDCCRateLuma[], + double NetDCCRateChroma[], + double DCCFractionOfZeroSizeRequestsLuma[], + double DCCFractionOfZeroSizeRequestsChroma[], + int HTotal[], + int VTotal[], + double PixelClock[], + double VRatio[], + enum scan_direction_class SourceScan[], + int BlockHeight256BytesY[], + int BlockWidth256BytesY[], + int BlockHeight256BytesC[], + int BlockWidth256BytesC[], + int DCCYMaxUncompressedBlock[], + int DCCCMaxUncompressedBlock[], + int VActive[], + bool DCCEnable[], + bool WritebackEnable[], + double ReadBandwidthPlaneLuma[], + double ReadBandwidthPlaneChroma[], + double meta_row_bw[], + double dpte_row_bw[], + double *StutterEfficiencyNotIncludingVBlank, + double *StutterEfficiency, + int *NumberOfStutterBurstsPerFrame, + double *Z8StutterEfficiencyNotIncludingVBlank, + double *Z8StutterEfficiency, + int *Z8NumberOfStutterBurstsPerFrame, + double *StutterPeriod); + +static void CalculateSwathAndDETConfiguration( + bool ForceSingleDPP, + int NumberOfActivePlanes, + unsigned int DETBufferSizeInKByte, + double MaximumSwathWidthLuma[], + double MaximumSwathWidthChroma[], + enum scan_direction_class SourceScan[], + enum source_format_class SourcePixelFormat[], + enum dm_swizzle_mode SurfaceTiling[], + int ViewportWidth[], + int ViewportHeight[], + int SurfaceWidthY[], + int SurfaceWidthC[], + int SurfaceHeightY[], + int SurfaceHeightC[], + int Read256BytesBlockHeightY[], + int Read256BytesBlockHeightC[], + int Read256BytesBlockWidthY[], + int Read256BytesBlockWidthC[], + enum odm_combine_mode ODMCombineEnabled[], + int BlendingAndTiming[], + int BytePerPixY[], + int BytePerPixC[], + double BytePerPixDETY[], + double BytePerPixDETC[], + int HActive[], + double HRatio[], + double HRatioChroma[], + int DPPPerPlane[], + int swath_width_luma_ub[], + int swath_width_chroma_ub[], + double SwathWidth[], + double SwathWidthChroma[], + int SwathHeightY[], + int SwathHeightC[], + unsigned int DETBufferSizeY[], + unsigned int DETBufferSizeC[], + bool ViewportSizeSupportPerPlane[], + bool *ViewportSizeSupport); +static void CalculateSwathWidth( + bool ForceSingleDPP, + int NumberOfActivePlanes, + enum source_format_class SourcePixelFormat[], + enum scan_direction_class SourceScan[], + int ViewportWidth[], + int ViewportHeight[], + int SurfaceWidthY[], + int SurfaceWidthC[], + int SurfaceHeightY[], + int SurfaceHeightC[], + enum odm_combine_mode ODMCombineEnabled[], + int BytePerPixY[], + int BytePerPixC[], + int Read256BytesBlockHeightY[], + int Read256BytesBlockHeightC[], + int Read256BytesBlockWidthY[], + int Read256BytesBlockWidthC[], + int BlendingAndTiming[], + int HActive[], + double HRatio[], + int DPPPerPlane[], + double SwathWidthSingleDPPY[], + double SwathWidthSingleDPPC[], + double SwathWidthY[], + double SwathWidthC[], + int MaximumSwathHeightY[], + int MaximumSwathHeightC[], + int swath_width_luma_ub[], + int swath_width_chroma_ub[]); + +static double CalculateExtraLatency( + int RoundTripPingLatencyCycles, + int ReorderingBytes, + double DCFCLK, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + double ReturnBW, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + int dpte_group_bytes[], + double HostVMInefficiencyFactor, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels); + +static double CalculateExtraLatencyBytes( + int ReorderingBytes, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + int dpte_group_bytes[], + double HostVMInefficiencyFactor, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels); + +static double CalculateUrgentLatency( + double UrgentLatencyPixelDataOnly, + double UrgentLatencyPixelMixedWithVMData, + double UrgentLatencyVMDataOnly, + bool DoUrgentLatencyAdjustment, + double UrgentLatencyAdjustmentFabricClockComponent, + double UrgentLatencyAdjustmentFabricClockReference, + double FabricClockSingle); + +static void CalculateUnboundedRequestAndCompressedBufferSize( + unsigned int DETBufferSizeInKByte, + int ConfigReturnBufferSizeInKByte, + enum unbounded_requesting_policy UseUnboundedRequestingFinal, + int TotalActiveDPP, + bool NoChromaPlanes, + int MaxNumDPP, + int CompressedBufferSegmentSizeInkByteFinal, + enum output_encoder_class *Output, + bool *UnboundedRequestEnabled, + int *CompressedBufferSizeInkByte); + +static bool UnboundedRequest(enum unbounded_requesting_policy UseUnboundedRequestingFinal, int TotalNumberOfActiveDPP, bool NoChroma, enum output_encoder_class Output); + +void dml31_recalculate(struct display_mode_lib *mode_lib) +{ + ModeSupportAndSystemConfiguration(mode_lib); + PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib); + DisplayPipeConfiguration(mode_lib); +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Calling DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation\n", __func__); +#endif + DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(mode_lib); +} + +static unsigned int dscceComputeDelay( + unsigned int bpc, + double BPP, + unsigned int sliceWidth, + unsigned int numSlices, + enum output_format_class pixelFormat, + enum output_encoder_class Output) +{ + // valid bpc = source bits per component in the set of {8, 10, 12} + // valid bpp = increments of 1/16 of a bit + // min = 6/7/8 in N420/N422/444, respectively + // max = such that compression is 1:1 + //valid sliceWidth = number of pixels per slice line, must be less than or equal to 5184/numSlices (or 4096/numSlices in 420 mode) + //valid numSlices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4} + //valid pixelFormat = pixel/color format in the set of {:N444_RGB, :S422, :N422, :N420} + + // fixed value + unsigned int rcModelSize = 8192; + + // N422/N420 operate at 2 pixels per clock + unsigned int pixelsPerClock = 0, lstall, D, initalXmitDelay, w, s, ix, wx, P, l0, a, ax, L, Delay, pixels; + + if (pixelFormat == dm_420) + pixelsPerClock = 2; + else if (pixelFormat == dm_444) + pixelsPerClock = 1; + else if (pixelFormat == dm_n422) + pixelsPerClock = 2; + // #all other modes operate at 1 pixel per clock + else + pixelsPerClock = 1; + + //initial transmit delay as per PPS + initalXmitDelay = dml_round(rcModelSize / 2.0 / BPP / pixelsPerClock); + + //compute ssm delay + if (bpc == 8) + D = 81; + else if (bpc == 10) + D = 89; + else + D = 113; + + //divide by pixel per cycle to compute slice width as seen by DSC + w = sliceWidth / pixelsPerClock; + + //422 mode has an additional cycle of delay + if (pixelFormat == dm_420 || pixelFormat == dm_444 || pixelFormat == dm_n422) + s = 0; + else + s = 1; + + //main calculation for the dscce + ix = initalXmitDelay + 45; + wx = (w + 2) / 3; + P = 3 * wx - w; + l0 = ix / w; + a = ix + P * l0; + ax = (a + 2) / 3 + D + 6 + 1; + L = (ax + wx - 1) / wx; + if ((ix % w) == 0 && P != 0) + lstall = 1; + else + lstall = 0; + Delay = L * wx * (numSlices - 1) + ax + s + lstall + 22; + + //dsc processes 3 pixel containers per cycle and a container can contain 1 or 2 pixels + pixels = Delay * 3 * pixelsPerClock; + return pixels; +} + +static unsigned int dscComputeDelay(enum output_format_class pixelFormat, enum output_encoder_class Output) +{ + unsigned int Delay = 0; + + if (pixelFormat == dm_420) { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 0; + // dscc - input deserializer + Delay = Delay + 3; + // dscc gets pixels every other cycle + Delay = Delay + 2; + // dscc - input cdc fifo + Delay = Delay + 12; + // dscc gets pixels every other cycle + Delay = Delay + 13; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 7; + // dscc gets pixels every other cycle + Delay = Delay + 3; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output serializer + Delay = Delay + 1; + // sft + Delay = Delay + 1; + } else if (pixelFormat == dm_n422) { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 1; + // dscc - input deserializer + Delay = Delay + 5; + // dscc - input cdc fifo + Delay = Delay + 25; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 10; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output serializer + Delay = Delay + 1; + // sft + Delay = Delay + 1; + } else { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 0; + // dscc - input deserializer + Delay = Delay + 3; + // dscc - input cdc fifo + Delay = Delay + 12; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 7; + // dscc - output serializer + Delay = Delay + 1; + // dscc - cdc uncertainty + Delay = Delay + 2; + // sft + Delay = Delay + 1; + } + + return Delay; +} + +static bool CalculatePrefetchSchedule( + struct display_mode_lib *mode_lib, + double HostVMInefficiencyFactor, + Pipe *myPipe, + unsigned int DSCDelay, + double DPPCLKDelaySubtotalPlusCNVCFormater, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int DPP_RECOUT_WIDTH, + enum output_format_class OutputFormat, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int MaxVStartup, + unsigned int GPUVMPageTableLevels, + bool GPUVMEnable, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + double HostVMMinPageSize, + bool DynamicMetadataEnable, + bool DynamicMetadataVMEnabled, + int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + double UrgentLatency, + double UrgentExtraLatency, + double TCalc, + unsigned int PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + double PrefetchSourceLinesY, + unsigned int SwathWidthY, + double VInitPreFillY, + unsigned int MaxNumSwathY, + double PrefetchSourceLinesC, + unsigned int SwathWidthC, + double VInitPreFillC, + unsigned int MaxNumSwathC, + int swath_width_luma_ub, + int swath_width_chroma_ub, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double TWait, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBWLuma, + double *RequiredPrefetchPixDataBWChroma, + bool *NotEnoughTimeForDynamicMetadata, + double *Tno_bw, + double *prefetch_vmrow_bw, + double *Tdmdl_vm, + double *Tdmdl, + double *TSetup, + int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix) +{ + bool MyError = false; + unsigned int DPPCycles, DISPCLKCycles; + double DSTTotalPixelsAfterScaler; + double LineTime; + double dst_y_prefetch_equ; + double Tsw_oto; + double prefetch_bw_oto; + double Tvm_oto; + double Tr0_oto; + double Tvm_oto_lines; + double Tr0_oto_lines; + double dst_y_prefetch_oto; + double TimeForFetchingMetaPTE = 0; + double TimeForFetchingRowInVBlank = 0; + double LinesToRequestPrefetchPixelData = 0; + unsigned int HostVMDynamicLevelsTrips; + double trip_to_mem; + double Tvm_trips; + double Tr0_trips; + double Tvm_trips_rounded; + double Tr0_trips_rounded; + double Lsw_oto; + double Tpre_rounded; + double prefetch_bw_equ; + double Tvm_equ; + double Tr0_equ; + double Tdmbf; + double Tdmec; + double Tdmsks; + double prefetch_sw_bytes; + double bytes_pp; + double dep_bytes; + int max_vratio_pre = 4; + double min_Lsw; + double Tsw_est1 = 0; + double Tsw_est3 = 0; + + if (GPUVMEnable == true && HostVMEnable == true) { + HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels; + } else { + HostVMDynamicLevelsTrips = 0; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: GPUVMEnable=%d HostVMEnable=%d HostVMInefficiencyFactor=%f\n", __func__, GPUVMEnable, HostVMEnable, HostVMInefficiencyFactor); +#endif + CalculateVupdateAndDynamicMetadataParameters( + MaxInterDCNTileRepeaters, + myPipe->DPPCLK, + myPipe->DISPCLK, + myPipe->DCFCLKDeepSleep, + myPipe->PixelClock, + myPipe->HTotal, + myPipe->VBlank, + DynamicMetadataTransmittedBytes, + DynamicMetadataLinesBeforeActiveRequired, + myPipe->InterlaceEnable, + myPipe->ProgressiveToInterlaceUnitInOPP, + TSetup, + &Tdmbf, + &Tdmec, + &Tdmsks, + VUpdateOffsetPix, + VUpdateWidthPix, + VReadyOffsetPix); + + LineTime = myPipe->HTotal / myPipe->PixelClock; + trip_to_mem = UrgentLatency; + Tvm_trips = UrgentExtraLatency + trip_to_mem * (GPUVMPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1); + +#ifdef __DML_VBA_ALLOW_DELTA__ + if (DynamicMetadataVMEnabled == true && GPUVMEnable == true) { +#else + if (DynamicMetadataVMEnabled == true) { +#endif + *Tdmdl = TWait + Tvm_trips + trip_to_mem; + } else { + *Tdmdl = TWait + UrgentExtraLatency; + } + +#ifdef __DML_VBA_ALLOW_DELTA__ + if (DynamicMetadataEnable == false) { + *Tdmdl = 0.0; + } +#endif + + if (DynamicMetadataEnable == true) { + if (VStartup * LineTime < *TSetup + *Tdmdl + Tdmbf + Tdmec + Tdmsks) { + *NotEnoughTimeForDynamicMetadata = true; + dml_print("DML::%s: Not Enough Time for Dynamic Meta!\n", __func__); + dml_print("DML::%s: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", __func__, Tdmbf); + dml_print("DML::%s: Tdmec: %fus - time dio takes to transfer dmd\n", __func__, Tdmec); + dml_print("DML::%s: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", __func__, Tdmsks); + dml_print("DML::%s: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", __func__, *Tdmdl); + } else { + *NotEnoughTimeForDynamicMetadata = false; + } + } else { + *NotEnoughTimeForDynamicMetadata = false; + } + + *Tdmdl_vm = (DynamicMetadataEnable == true && DynamicMetadataVMEnabled == true && GPUVMEnable == true ? TWait + Tvm_trips : 0); + + if (myPipe->ScalerEnabled) + DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCL; + else + DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCLLBOnly; + + DPPCycles = DPPCycles + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor; + + DISPCLKCycles = DISPCLKDelaySubtotal; + + if (myPipe->DPPCLK == 0.0 || myPipe->DISPCLK == 0.0) + return true; + + *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK + DSCDelay; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: DPPCycles: %d\n", __func__, DPPCycles); + dml_print("DML::%s: PixelClock: %f\n", __func__, myPipe->PixelClock); + dml_print("DML::%s: DPPCLK: %f\n", __func__, myPipe->DPPCLK); + dml_print("DML::%s: DISPCLKCycles: %d\n", __func__, DISPCLKCycles); + dml_print("DML::%s: DISPCLK: %f\n", __func__, myPipe->DISPCLK); + dml_print("DML::%s: DSCDelay: %d\n", __func__, DSCDelay); + dml_print("DML::%s: DSTXAfterScaler: %d\n", __func__, *DSTXAfterScaler); + dml_print("DML::%s: ODMCombineIsEnabled: %d\n", __func__, myPipe->ODMCombineIsEnabled); +#endif + + *DSTXAfterScaler = *DSTXAfterScaler + ((myPipe->ODMCombineIsEnabled) ? 18 : 0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH; + + if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && myPipe->ProgressiveToInterlaceUnitInOPP)) + *DSTYAfterScaler = 1; + else + *DSTYAfterScaler = 0; + + DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler; + *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1); + *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal)); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: DSTXAfterScaler: %d (final)\n", __func__, *DSTXAfterScaler); +#endif + + MyError = false; + + Tr0_trips = trip_to_mem * (HostVMDynamicLevelsTrips + 1); + Tvm_trips_rounded = dml_ceil(4.0 * Tvm_trips / LineTime, 1) / 4 * LineTime; + Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1) / 4 * LineTime; + +#ifdef __DML_VBA_ALLOW_DELTA__ + if (!myPipe->DCCEnable) { + Tr0_trips = 0.0; + Tr0_trips_rounded = 0.0; + } +#endif + + if (!GPUVMEnable) { + Tvm_trips = 0.0; + Tvm_trips_rounded = 0.0; + } + + if (GPUVMEnable) { + if (GPUVMPageTableLevels >= 3) { + *Tno_bw = UrgentExtraLatency + trip_to_mem * ((GPUVMPageTableLevels - 2) - 1); + } else { + *Tno_bw = 0; + } + } else if (!myPipe->DCCEnable) { + *Tno_bw = LineTime; + } else { + *Tno_bw = LineTime / 4; + } + + if (myPipe->SourcePixelFormat == dm_420_8 || myPipe->SourcePixelFormat == dm_420_10 || myPipe->SourcePixelFormat == dm_420_12) + bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC / 4; + else + bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC; + + prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC; + prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime)); + + min_Lsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre; + Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4; + Tsw_oto = Lsw_oto * LineTime; + + prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC) / Tsw_oto; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML: HTotal: %d\n", myPipe->HTotal); + dml_print("DML: prefetch_bw_oto: %f\n", prefetch_bw_oto); + dml_print("DML: PrefetchSourceLinesY: %f\n", PrefetchSourceLinesY); + dml_print("DML: swath_width_luma_ub: %d\n", swath_width_luma_ub); + dml_print("DML: BytePerPixelY: %d\n", myPipe->BytePerPixelY); + dml_print("DML: Tsw_oto: %f\n", Tsw_oto); +#endif + + if (GPUVMEnable == true) + Tvm_oto = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto, Tvm_trips, LineTime / 4.0); + else + Tvm_oto = LineTime / 4.0; + + if ((GPUVMEnable == true || myPipe->DCCEnable == true)) { + Tr0_oto = dml_max4((MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto, Tr0_trips, // PREVIOUS_ERROR (missing this term) + LineTime - Tvm_oto, + LineTime / 4); + } else { + Tr0_oto = (LineTime - Tvm_oto) / 2.0; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Tvm_trips = %f\n", __func__, Tvm_trips); + dml_print("DML::%s: Tr0_trips = %f\n", __func__, Tr0_trips); + dml_print("DML::%s: PDEAndMetaPTEBytesFrame = %d\n", __func__, MetaRowByte); + dml_print("DML::%s: MetaRowByte = %d\n", __func__, MetaRowByte); + dml_print("DML::%s: PixelPTEBytesPerRow = %d\n", __func__, PixelPTEBytesPerRow); + dml_print("DML::%s: HostVMInefficiencyFactor = %f\n", __func__, HostVMInefficiencyFactor); + dml_print("DML::%s: prefetch_bw_oto = %f\n", __func__, prefetch_bw_oto); + dml_print("DML::%s: Tr0_oto = %f\n", __func__, Tr0_oto); + dml_print("DML::%s: Tvm_oto = %f\n", __func__, Tvm_oto); +#endif + + Tvm_oto_lines = dml_ceil(4.0 * Tvm_oto / LineTime, 1) / 4.0; + Tr0_oto_lines = dml_ceil(4.0 * Tr0_oto / LineTime, 1) / 4.0; + dst_y_prefetch_oto = Tvm_oto_lines + 2 * Tr0_oto_lines + Lsw_oto; + dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal); + dst_y_prefetch_equ = dml_floor(4.0 * (dst_y_prefetch_equ + 0.125), 1) / 4.0; + Tpre_rounded = dst_y_prefetch_equ * LineTime; + + dep_bytes = dml_max(PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor, MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor); + + if (prefetch_sw_bytes < dep_bytes) + prefetch_sw_bytes = 2 * dep_bytes; + + dml_print("DML: dst_y_prefetch_oto: %f\n", dst_y_prefetch_oto); + dml_print("DML: Tvm_oto_lines: %f\n", Tvm_oto_lines); + dml_print("DML: Tr0_oto_lines: %f\n", Tr0_oto_lines); + dml_print("DML: Lsw_oto: %f\n", Lsw_oto); + dml_print("DML: LineTime: %f\n", LineTime); + dml_print("DML: dst_y_prefetch_equ: %f (after round)\n", dst_y_prefetch_equ); + + dml_print("DML: LineTime: %f\n", LineTime); + dml_print("DML: VStartup: %d\n", VStartup); + dml_print("DML: Tvstartup: %fus - time between vstartup and first pixel of active\n", VStartup * LineTime); + dml_print("DML: TSetup: %fus - time from vstartup to vready\n", *TSetup); + dml_print("DML: TCalc: %fus - time for calculations in dchub starting at vready\n", TCalc); + dml_print("DML: TWait: %fus - time for fabric to become ready max(pstate exit,cstate enter/exit, urgent latency) after TCalc\n", TWait); + dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf); + dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec); + dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks); + dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", *Tdmdl_vm); + dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl); + dml_print("DML: DSTXAfterScaler: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", *DSTXAfterScaler); + dml_print("DML: DSTYAfterScaler: %f lines - number of lines of pipeline and buffer delay after scaler \n", *DSTYAfterScaler); + + *PrefetchBandwidth = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + if (dst_y_prefetch_equ > 1) { + double PrefetchBandwidth1; + double PrefetchBandwidth2; + double PrefetchBandwidth3; + double PrefetchBandwidth4; + + if (Tpre_rounded - *Tno_bw > 0) { + PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor + + prefetch_sw_bytes) / (Tpre_rounded - *Tno_bw); + Tsw_est1 = prefetch_sw_bytes / PrefetchBandwidth1; + } else { + PrefetchBandwidth1 = 0; + } + + if (VStartup == MaxVStartup && Tsw_est1 / LineTime < min_Lsw && Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - *Tno_bw > 0) { + PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) + / (Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - *Tno_bw); + } + + if (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded > 0) + PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + prefetch_sw_bytes) / (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded); + else + PrefetchBandwidth2 = 0; + + if (Tpre_rounded - Tvm_trips_rounded > 0) { + PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor + + prefetch_sw_bytes) / (Tpre_rounded - Tvm_trips_rounded); + Tsw_est3 = prefetch_sw_bytes / PrefetchBandwidth3; + } else { + PrefetchBandwidth3 = 0; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Tpre_rounded: %f\n", __func__, Tpre_rounded); + dml_print("DML::%s: Tvm_trips_rounded: %f\n", __func__, Tvm_trips_rounded); + dml_print("DML::%s: PrefetchBandwidth3: %f\n", __func__, PrefetchBandwidth3); +#endif + if (VStartup == MaxVStartup && Tsw_est3 / LineTime < min_Lsw && Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - Tvm_trips_rounded > 0) { + PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) + / (Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - Tvm_trips_rounded); + } + + if (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded > 0) + PrefetchBandwidth4 = prefetch_sw_bytes / (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded); + else + PrefetchBandwidth4 = 0; + + { + bool Case1OK; + bool Case2OK; + bool Case3OK; + + if (PrefetchBandwidth1 > 0) { + if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1 >= Tvm_trips_rounded + && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth1 >= Tr0_trips_rounded) { + Case1OK = true; + } else { + Case1OK = false; + } + } else { + Case1OK = false; + } + + if (PrefetchBandwidth2 > 0) { + if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2 >= Tvm_trips_rounded + && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth2 < Tr0_trips_rounded) { + Case2OK = true; + } else { + Case2OK = false; + } + } else { + Case2OK = false; + } + + if (PrefetchBandwidth3 > 0) { + if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3 < Tvm_trips_rounded + && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth3 >= Tr0_trips_rounded) { + Case3OK = true; + } else { + Case3OK = false; + } + } else { + Case3OK = false; + } + + if (Case1OK) { + prefetch_bw_equ = PrefetchBandwidth1; + } else if (Case2OK) { + prefetch_bw_equ = PrefetchBandwidth2; + } else if (Case3OK) { + prefetch_bw_equ = PrefetchBandwidth3; + } else { + prefetch_bw_equ = PrefetchBandwidth4; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Case1OK: %d\n", __func__, Case1OK); + dml_print("DML::%s: Case2OK: %d\n", __func__, Case2OK); + dml_print("DML::%s: Case3OK: %d\n", __func__, Case3OK); + dml_print("DML::%s: prefetch_bw_equ: %f\n", __func__, prefetch_bw_equ); +#endif + + if (prefetch_bw_equ > 0) { + if (GPUVMEnable == true) { + Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4); + } else { + Tvm_equ = LineTime / 4; + } + + if ((GPUVMEnable == true || myPipe->DCCEnable == true)) { + Tr0_equ = dml_max4( + (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_equ, + Tr0_trips, + (LineTime - Tvm_equ) / 2, + LineTime / 4); + } else { + Tr0_equ = (LineTime - Tvm_equ) / 2; + } + } else { + Tvm_equ = 0; + Tr0_equ = 0; + dml_print("DML: prefetch_bw_equ equals 0! %s:%d\n", __FILE__, __LINE__); + } + } + + if (dst_y_prefetch_oto < dst_y_prefetch_equ) { + *DestinationLinesForPrefetch = dst_y_prefetch_oto; + TimeForFetchingMetaPTE = Tvm_oto; + TimeForFetchingRowInVBlank = Tr0_oto; + *PrefetchBandwidth = prefetch_bw_oto; + } else { + *DestinationLinesForPrefetch = dst_y_prefetch_equ; + TimeForFetchingMetaPTE = Tvm_equ; + TimeForFetchingRowInVBlank = Tr0_equ; + *PrefetchBandwidth = prefetch_bw_equ; + } + + *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * TimeForFetchingMetaPTE / LineTime, 1.0) / 4.0; + + *DestinationLinesToRequestRowInVBlank = dml_ceil(4.0 * TimeForFetchingRowInVBlank / LineTime, 1.0) / 4.0; + +#ifdef __DML_VBA_ALLOW_DELTA__ + LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch + // See note above dated 5/30/2018 + // - ((NumberOfCursors > 0 || GPUVMEnable || DCCEnable) ? + - ((GPUVMEnable || myPipe->DCCEnable) ? (*DestinationLinesToRequestVMInVBlank + 2 * *DestinationLinesToRequestRowInVBlank) : 0.0); // TODO: Did someone else add this?? +#else + LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch - *DestinationLinesToRequestVMInVBlank - 2 * *DestinationLinesToRequestRowInVBlank; +#endif + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: DestinationLinesForPrefetch = %f\n", __func__, *DestinationLinesForPrefetch); + dml_print("DML::%s: DestinationLinesToRequestVMInVBlank = %f\n", __func__, *DestinationLinesToRequestVMInVBlank); + dml_print("DML::%s: TimeForFetchingRowInVBlank = %f\n", __func__, TimeForFetchingRowInVBlank); + dml_print("DML::%s: LineTime = %f\n", __func__, LineTime); + dml_print("DML::%s: DestinationLinesToRequestRowInVBlank = %f\n", __func__, *DestinationLinesToRequestRowInVBlank); + dml_print("DML::%s: PrefetchSourceLinesY = %f\n", __func__, PrefetchSourceLinesY); + dml_print("DML::%s: LinesToRequestPrefetchPixelData = %f\n", __func__, LinesToRequestPrefetchPixelData); +#endif + + if (LinesToRequestPrefetchPixelData > 0 && prefetch_bw_equ > 0) { + + *VRatioPrefetchY = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData; + *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VRatioPrefetchY = %f\n", __func__, *VRatioPrefetchY); + dml_print("DML::%s: SwathHeightY = %d\n", __func__, SwathHeightY); + dml_print("DML::%s: VInitPreFillY = %f\n", __func__, VInitPreFillY); +#endif + if ((SwathHeightY > 4) && (VInitPreFillY > 3)) { + if (LinesToRequestPrefetchPixelData > (VInitPreFillY - 3.0) / 2.0) { + *VRatioPrefetchY = dml_max( + (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData, + (double) MaxNumSwathY * SwathHeightY / (LinesToRequestPrefetchPixelData - (VInitPreFillY - 3.0) / 2.0)); + *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); + } else { + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + *VRatioPrefetchY = 0; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VRatioPrefetchY = %f\n", __func__, *VRatioPrefetchY); + dml_print("DML::%s: PrefetchSourceLinesY = %f\n", __func__, PrefetchSourceLinesY); + dml_print("DML::%s: MaxNumSwathY = %d\n", __func__, MaxNumSwathY); +#endif + } + + *VRatioPrefetchC = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData; + *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VRatioPrefetchC = %f\n", __func__, *VRatioPrefetchC); + dml_print("DML::%s: SwathHeightC = %d\n", __func__, SwathHeightC); + dml_print("DML::%s: VInitPreFillC = %f\n", __func__, VInitPreFillC); +#endif + if ((SwathHeightC > 4)) { + if (LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) { + *VRatioPrefetchC = dml_max( + *VRatioPrefetchC, + (double) MaxNumSwathC * SwathHeightC / (LinesToRequestPrefetchPixelData - (VInitPreFillC - 3.0) / 2.0)); + *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); + } else { + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + *VRatioPrefetchC = 0; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VRatioPrefetchC = %f\n", __func__, *VRatioPrefetchC); + dml_print("DML::%s: PrefetchSourceLinesC = %f\n", __func__, PrefetchSourceLinesC); + dml_print("DML::%s: MaxNumSwathC = %d\n", __func__, MaxNumSwathC); +#endif + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: BytePerPixelY = %d\n", __func__, myPipe->BytePerPixelY); + dml_print("DML::%s: swath_width_luma_ub = %d\n", __func__, swath_width_luma_ub); + dml_print("DML::%s: LineTime = %f\n", __func__, LineTime); +#endif + + *RequiredPrefetchPixDataBWLuma = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData * myPipe->BytePerPixelY * swath_width_luma_ub / LineTime; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: RequiredPrefetchPixDataBWLuma = %f\n", __func__, *RequiredPrefetchPixDataBWLuma); +#endif + + *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * myPipe->BytePerPixelC * swath_width_chroma_ub + / LineTime; + } else { + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + dml_print("DML: LinesToRequestPrefetchPixelData: %f, should be > 0\n", LinesToRequestPrefetchPixelData); + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + *RequiredPrefetchPixDataBWChroma = 0; + } + + dml_print( + "DML: Tpre: %fus - sum of time to request meta pte, 2 x data pte + meta data, swaths\n", + (double) LinesToRequestPrefetchPixelData * LineTime + 2.0 * TimeForFetchingRowInVBlank + TimeForFetchingMetaPTE); + dml_print("DML: Tvm: %fus - time to fetch page tables for meta surface\n", TimeForFetchingMetaPTE); + dml_print("DML: Tr0: %fus - time to fetch first row of data pagetables and first row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank); + dml_print( + "DML: Tsw: %fus = time to fetch enough pixel data and cursor data to feed the scalers init position and detile\n", + (double) LinesToRequestPrefetchPixelData * LineTime); + dml_print("DML: To: %fus - time for propagation from scaler to optc\n", + (*DSTYAfterScaler + ((double) (*DSTXAfterScaler) / + (double) myPipe->HTotal)) * LineTime); + dml_print("DML: Tvstartup - TSetup - Tcalc - Twait - Tpre - To > 0\n"); + dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", + VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank + - (*DSTYAfterScaler + ((double) (*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - *TSetup); + dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n", PixelPTEBytesPerRow); + + } else { + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + } + + { + double prefetch_vm_bw; + double prefetch_row_bw; + + if (PDEAndMetaPTEBytesFrame == 0) { + prefetch_vm_bw = 0; + } else if (*DestinationLinesToRequestVMInVBlank > 0) { +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: PDEAndMetaPTEBytesFrame = %d\n", __func__, PDEAndMetaPTEBytesFrame); + dml_print("DML::%s: HostVMInefficiencyFactor = %f\n", __func__, HostVMInefficiencyFactor); + dml_print("DML::%s: DestinationLinesToRequestVMInVBlank = %f\n", __func__, *DestinationLinesToRequestVMInVBlank); + dml_print("DML::%s: LineTime = %f\n", __func__, LineTime); +#endif + prefetch_vm_bw = PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInVBlank * LineTime); +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: prefetch_vm_bw = %f\n", __func__, prefetch_vm_bw); +#endif + } else { + prefetch_vm_bw = 0; + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + } + + if (MetaRowByte + PixelPTEBytesPerRow == 0) { + prefetch_row_bw = 0; + } else if (*DestinationLinesToRequestRowInVBlank > 0) { + prefetch_row_bw = (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInVBlank * LineTime); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: MetaRowByte = %d\n", __func__, MetaRowByte); + dml_print("DML::%s: PixelPTEBytesPerRow = %d\n", __func__, PixelPTEBytesPerRow); + dml_print("DML::%s: DestinationLinesToRequestRowInVBlank = %f\n", __func__, *DestinationLinesToRequestRowInVBlank); + dml_print("DML::%s: prefetch_row_bw = %f\n", __func__, prefetch_row_bw); +#endif + } else { + prefetch_row_bw = 0; + MyError = true; + dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); + } + + *prefetch_vmrow_bw = dml_max(prefetch_vm_bw, prefetch_row_bw); + } + + if (MyError) { + *PrefetchBandwidth = 0; + TimeForFetchingMetaPTE = 0; + TimeForFetchingRowInVBlank = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *DestinationLinesForPrefetch = 0; + LinesToRequestPrefetchPixelData = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + *RequiredPrefetchPixDataBWChroma = 0; + } + + return MyError; +} + +static double RoundToDFSGranularityUp(double Clock, double VCOSpeed) +{ + return VCOSpeed * 4 / dml_floor(VCOSpeed * 4 / Clock, 1); +} + +static double RoundToDFSGranularityDown(double Clock, double VCOSpeed) +{ + return VCOSpeed * 4 / dml_ceil(VCOSpeed * 4.0 / Clock, 1); +} + +static void CalculateDCCConfiguration( + bool DCCEnabled, + bool DCCProgrammingAssumesScanDirectionUnknown, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceWidthLuma, + unsigned int SurfaceWidthChroma, + unsigned int SurfaceHeightLuma, + unsigned int SurfaceHeightChroma, + double DETBufferSize, + unsigned int RequestHeight256ByteLuma, + unsigned int RequestHeight256ByteChroma, + enum dm_swizzle_mode TilingFormat, + unsigned int BytePerPixelY, + unsigned int BytePerPixelC, + double BytePerPixelDETY, + double BytePerPixelDETC, + enum scan_direction_class ScanOrientation, + unsigned int *MaxUncompressedBlockLuma, + unsigned int *MaxUncompressedBlockChroma, + unsigned int *MaxCompressedBlockLuma, + unsigned int *MaxCompressedBlockChroma, + unsigned int *IndependentBlockLuma, + unsigned int *IndependentBlockChroma) +{ + int yuv420; + int horz_div_l; + int horz_div_c; + int vert_div_l; + int vert_div_c; + + int swath_buf_size; + double detile_buf_vp_horz_limit; + double detile_buf_vp_vert_limit; + + int MAS_vp_horz_limit; + int MAS_vp_vert_limit; + int max_vp_horz_width; + int max_vp_vert_height; + int eff_surf_width_l; + int eff_surf_width_c; + int eff_surf_height_l; + int eff_surf_height_c; + + int full_swath_bytes_horz_wc_l; + int full_swath_bytes_horz_wc_c; + int full_swath_bytes_vert_wc_l; + int full_swath_bytes_vert_wc_c; + int req128_horz_wc_l; + int req128_horz_wc_c; + int req128_vert_wc_l; + int req128_vert_wc_c; + int segment_order_horz_contiguous_luma; + int segment_order_horz_contiguous_chroma; + int segment_order_vert_contiguous_luma; + int segment_order_vert_contiguous_chroma; + + typedef enum { + REQ_256Bytes, REQ_128BytesNonContiguous, REQ_128BytesContiguous, REQ_NA + } RequestType; + RequestType RequestLuma; + RequestType RequestChroma; + + yuv420 = ((SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_420_12) ? 1 : 0); + horz_div_l = 1; + horz_div_c = 1; + vert_div_l = 1; + vert_div_c = 1; + + if (BytePerPixelY == 1) + vert_div_l = 0; + if (BytePerPixelC == 1) + vert_div_c = 0; + if (BytePerPixelY == 8 && (TilingFormat == dm_sw_64kb_s || TilingFormat == dm_sw_64kb_s_t || TilingFormat == dm_sw_64kb_s_x)) + horz_div_l = 0; + if (BytePerPixelC == 8 && (TilingFormat == dm_sw_64kb_s || TilingFormat == dm_sw_64kb_s_t || TilingFormat == dm_sw_64kb_s_x)) + horz_div_c = 0; + + if (BytePerPixelC == 0) { + swath_buf_size = DETBufferSize / 2 - 2 * 256; + detile_buf_vp_horz_limit = (double) swath_buf_size / ((double) RequestHeight256ByteLuma * BytePerPixelY / (1 + horz_div_l)); + detile_buf_vp_vert_limit = (double) swath_buf_size / (256.0 / RequestHeight256ByteLuma / (1 + vert_div_l)); + } else { + swath_buf_size = DETBufferSize / 2 - 2 * 2 * 256; + detile_buf_vp_horz_limit = (double) swath_buf_size + / ((double) RequestHeight256ByteLuma * BytePerPixelY / (1 + horz_div_l) + + (double) RequestHeight256ByteChroma * BytePerPixelC / (1 + horz_div_c) / (1 + yuv420)); + detile_buf_vp_vert_limit = (double) swath_buf_size + / (256.0 / RequestHeight256ByteLuma / (1 + vert_div_l) + 256.0 / RequestHeight256ByteChroma / (1 + vert_div_c) / (1 + yuv420)); + } + + if (SourcePixelFormat == dm_420_10) { + detile_buf_vp_horz_limit = 1.5 * detile_buf_vp_horz_limit; + detile_buf_vp_vert_limit = 1.5 * detile_buf_vp_vert_limit; + } + + detile_buf_vp_horz_limit = dml_floor(detile_buf_vp_horz_limit - 1, 16); + detile_buf_vp_vert_limit = dml_floor(detile_buf_vp_vert_limit - 1, 16); + + MAS_vp_horz_limit = SourcePixelFormat == dm_rgbe_alpha ? 3840 : 5760; + MAS_vp_vert_limit = (BytePerPixelC > 0 ? 2880 : 5760); + max_vp_horz_width = dml_min((double) MAS_vp_horz_limit, detile_buf_vp_horz_limit); + max_vp_vert_height = dml_min((double) MAS_vp_vert_limit, detile_buf_vp_vert_limit); + eff_surf_width_l = (SurfaceWidthLuma > max_vp_horz_width ? max_vp_horz_width : SurfaceWidthLuma); + eff_surf_width_c = eff_surf_width_l / (1 + yuv420); + eff_surf_height_l = (SurfaceHeightLuma > max_vp_vert_height ? max_vp_vert_height : SurfaceHeightLuma); + eff_surf_height_c = eff_surf_height_l / (1 + yuv420); + + full_swath_bytes_horz_wc_l = eff_surf_width_l * RequestHeight256ByteLuma * BytePerPixelY; + full_swath_bytes_vert_wc_l = eff_surf_height_l * 256 / RequestHeight256ByteLuma; + if (BytePerPixelC > 0) { + full_swath_bytes_horz_wc_c = eff_surf_width_c * RequestHeight256ByteChroma * BytePerPixelC; + full_swath_bytes_vert_wc_c = eff_surf_height_c * 256 / RequestHeight256ByteChroma; + } else { + full_swath_bytes_horz_wc_c = 0; + full_swath_bytes_vert_wc_c = 0; + } + + if (SourcePixelFormat == dm_420_10) { + full_swath_bytes_horz_wc_l = dml_ceil(full_swath_bytes_horz_wc_l * 2 / 3, 256); + full_swath_bytes_horz_wc_c = dml_ceil(full_swath_bytes_horz_wc_c * 2 / 3, 256); + full_swath_bytes_vert_wc_l = dml_ceil(full_swath_bytes_vert_wc_l * 2 / 3, 256); + full_swath_bytes_vert_wc_c = dml_ceil(full_swath_bytes_vert_wc_c * 2 / 3, 256); + } + + if (2 * full_swath_bytes_horz_wc_l + 2 * full_swath_bytes_horz_wc_c <= DETBufferSize) { + req128_horz_wc_l = 0; + req128_horz_wc_c = 0; + } else if (full_swath_bytes_horz_wc_l < 1.5 * full_swath_bytes_horz_wc_c && 2 * full_swath_bytes_horz_wc_l + full_swath_bytes_horz_wc_c <= DETBufferSize) { + req128_horz_wc_l = 0; + req128_horz_wc_c = 1; + } else if (full_swath_bytes_horz_wc_l >= 1.5 * full_swath_bytes_horz_wc_c && full_swath_bytes_horz_wc_l + 2 * full_swath_bytes_horz_wc_c <= DETBufferSize) { + req128_horz_wc_l = 1; + req128_horz_wc_c = 0; + } else { + req128_horz_wc_l = 1; + req128_horz_wc_c = 1; + } + + if (2 * full_swath_bytes_vert_wc_l + 2 * full_swath_bytes_vert_wc_c <= DETBufferSize) { + req128_vert_wc_l = 0; + req128_vert_wc_c = 0; + } else if (full_swath_bytes_vert_wc_l < 1.5 * full_swath_bytes_vert_wc_c && 2 * full_swath_bytes_vert_wc_l + full_swath_bytes_vert_wc_c <= DETBufferSize) { + req128_vert_wc_l = 0; + req128_vert_wc_c = 1; + } else if (full_swath_bytes_vert_wc_l >= 1.5 * full_swath_bytes_vert_wc_c && full_swath_bytes_vert_wc_l + 2 * full_swath_bytes_vert_wc_c <= DETBufferSize) { + req128_vert_wc_l = 1; + req128_vert_wc_c = 0; + } else { + req128_vert_wc_l = 1; + req128_vert_wc_c = 1; + } + + if (BytePerPixelY == 2 || (BytePerPixelY == 4 && TilingFormat != dm_sw_64kb_r_x)) { + segment_order_horz_contiguous_luma = 0; + } else { + segment_order_horz_contiguous_luma = 1; + } + if ((BytePerPixelY == 8 && (TilingFormat == dm_sw_64kb_d || TilingFormat == dm_sw_64kb_d_x || TilingFormat == dm_sw_64kb_d_t || TilingFormat == dm_sw_64kb_r_x)) + || (BytePerPixelY == 4 && TilingFormat == dm_sw_64kb_r_x)) { + segment_order_vert_contiguous_luma = 0; + } else { + segment_order_vert_contiguous_luma = 1; + } + if (BytePerPixelC == 2 || (BytePerPixelC == 4 && TilingFormat != dm_sw_64kb_r_x)) { + segment_order_horz_contiguous_chroma = 0; + } else { + segment_order_horz_contiguous_chroma = 1; + } + if ((BytePerPixelC == 8 && (TilingFormat == dm_sw_64kb_d || TilingFormat == dm_sw_64kb_d_x || TilingFormat == dm_sw_64kb_d_t || TilingFormat == dm_sw_64kb_r_x)) + || (BytePerPixelC == 4 && TilingFormat == dm_sw_64kb_r_x)) { + segment_order_vert_contiguous_chroma = 0; + } else { + segment_order_vert_contiguous_chroma = 1; + } + + if (DCCProgrammingAssumesScanDirectionUnknown == true) { + if (req128_horz_wc_l == 0 && req128_vert_wc_l == 0) { + RequestLuma = REQ_256Bytes; + } else if ((req128_horz_wc_l == 1 && segment_order_horz_contiguous_luma == 0) || (req128_vert_wc_l == 1 && segment_order_vert_contiguous_luma == 0)) { + RequestLuma = REQ_128BytesNonContiguous; + } else { + RequestLuma = REQ_128BytesContiguous; + } + if (req128_horz_wc_c == 0 && req128_vert_wc_c == 0) { + RequestChroma = REQ_256Bytes; + } else if ((req128_horz_wc_c == 1 && segment_order_horz_contiguous_chroma == 0) || (req128_vert_wc_c == 1 && segment_order_vert_contiguous_chroma == 0)) { + RequestChroma = REQ_128BytesNonContiguous; + } else { + RequestChroma = REQ_128BytesContiguous; + } + } else if (ScanOrientation != dm_vert) { + if (req128_horz_wc_l == 0) { + RequestLuma = REQ_256Bytes; + } else if (segment_order_horz_contiguous_luma == 0) { + RequestLuma = REQ_128BytesNonContiguous; + } else { + RequestLuma = REQ_128BytesContiguous; + } + if (req128_horz_wc_c == 0) { + RequestChroma = REQ_256Bytes; + } else if (segment_order_horz_contiguous_chroma == 0) { + RequestChroma = REQ_128BytesNonContiguous; + } else { + RequestChroma = REQ_128BytesContiguous; + } + } else { + if (req128_vert_wc_l == 0) { + RequestLuma = REQ_256Bytes; + } else if (segment_order_vert_contiguous_luma == 0) { + RequestLuma = REQ_128BytesNonContiguous; + } else { + RequestLuma = REQ_128BytesContiguous; + } + if (req128_vert_wc_c == 0) { + RequestChroma = REQ_256Bytes; + } else if (segment_order_vert_contiguous_chroma == 0) { + RequestChroma = REQ_128BytesNonContiguous; + } else { + RequestChroma = REQ_128BytesContiguous; + } + } + + if (RequestLuma == REQ_256Bytes) { + *MaxUncompressedBlockLuma = 256; + *MaxCompressedBlockLuma = 256; + *IndependentBlockLuma = 0; + } else if (RequestLuma == REQ_128BytesContiguous) { + *MaxUncompressedBlockLuma = 256; + *MaxCompressedBlockLuma = 128; + *IndependentBlockLuma = 128; + } else { + *MaxUncompressedBlockLuma = 256; + *MaxCompressedBlockLuma = 64; + *IndependentBlockLuma = 64; + } + + if (RequestChroma == REQ_256Bytes) { + *MaxUncompressedBlockChroma = 256; + *MaxCompressedBlockChroma = 256; + *IndependentBlockChroma = 0; + } else if (RequestChroma == REQ_128BytesContiguous) { + *MaxUncompressedBlockChroma = 256; + *MaxCompressedBlockChroma = 128; + *IndependentBlockChroma = 128; + } else { + *MaxUncompressedBlockChroma = 256; + *MaxCompressedBlockChroma = 64; + *IndependentBlockChroma = 64; + } + + if (DCCEnabled != true || BytePerPixelC == 0) { + *MaxUncompressedBlockChroma = 0; + *MaxCompressedBlockChroma = 0; + *IndependentBlockChroma = 0; + } + + if (DCCEnabled != true) { + *MaxUncompressedBlockLuma = 0; + *MaxCompressedBlockLuma = 0; + *IndependentBlockLuma = 0; + } +} + +static double CalculatePrefetchSourceLines( + struct display_mode_lib *mode_lib, + double VRatio, + double vtaps, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + unsigned int SwathHeight, + unsigned int ViewportYStart, + double *VInitPreFill, + unsigned int *MaxNumSwath) +{ + struct vba_vars_st *v = &mode_lib->vba; + unsigned int MaxPartialSwath; + + if (ProgressiveToInterlaceUnitInOPP) + *VInitPreFill = dml_floor((VRatio + vtaps + 1) / 2.0, 1); + else + *VInitPreFill = dml_floor((VRatio + vtaps + 1 + Interlace * 0.5 * VRatio) / 2.0, 1); + + if (!v->IgnoreViewportPositioning) { + + *MaxNumSwath = dml_ceil((*VInitPreFill - 1.0) / SwathHeight, 1) + 1.0; + + if (*VInitPreFill > 1.0) + MaxPartialSwath = (unsigned int) (*VInitPreFill - 2) % SwathHeight; + else + MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 2) % SwathHeight; + MaxPartialSwath = dml_max(1U, MaxPartialSwath); + + } else { + + if (ViewportYStart != 0) + dml_print("WARNING DML: using viewport y position of 0 even though actual viewport y position is non-zero in prefetch source lines calculation\n"); + + *MaxNumSwath = dml_ceil(*VInitPreFill / SwathHeight, 1); + + if (*VInitPreFill > 1.0) + MaxPartialSwath = (unsigned int) (*VInitPreFill - 1) % SwathHeight; + else + MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 1) % SwathHeight; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VRatio = %f\n", __func__, VRatio); + dml_print("DML::%s: vtaps = %f\n", __func__, vtaps); + dml_print("DML::%s: VInitPreFill = %f\n", __func__, *VInitPreFill); + dml_print("DML::%s: ProgressiveToInterlaceUnitInOPP = %d\n", __func__, ProgressiveToInterlaceUnitInOPP); + dml_print("DML::%s: IgnoreViewportPositioning = %d\n", __func__, v->IgnoreViewportPositioning); + dml_print("DML::%s: SwathHeight = %d\n", __func__, SwathHeight); + dml_print("DML::%s: MaxPartialSwath = %d\n", __func__, MaxPartialSwath); + dml_print("DML::%s: MaxNumSwath = %d\n", __func__, *MaxNumSwath); + dml_print("DML::%s: Prefetch source lines = %d\n", __func__, *MaxNumSwath * SwathHeight + MaxPartialSwath); +#endif + return *MaxNumSwath * SwathHeight + MaxPartialSwath; +} + +static unsigned int CalculateVMAndRowBytes( + struct display_mode_lib *mode_lib, + bool DCCEnable, + unsigned int BlockHeight256Bytes, + unsigned int BlockWidth256Bytes, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceTiling, + unsigned int BytePerPixel, + enum scan_direction_class ScanDirection, + unsigned int SwathWidth, + unsigned int ViewportHeight, + bool GPUVMEnable, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + unsigned int GPUVMMinPageSize, + unsigned int HostVMMinPageSize, + unsigned int PTEBufferSizeInRequests, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + int *dpte_row_width_ub, + unsigned int *dpte_row_height, + unsigned int *MetaRequestWidth, + unsigned int *MetaRequestHeight, + unsigned int *meta_row_width, + unsigned int *meta_row_height, + int *vm_group_bytes, + unsigned int *dpte_group_bytes, + unsigned int *PixelPTEReqWidth, + unsigned int *PixelPTEReqHeight, + unsigned int *PTERequestSize, + int *DPDE0BytesFrame, + int *MetaPTEBytesFrame) +{ + struct vba_vars_st *v = &mode_lib->vba; + unsigned int MPDEBytesFrame; + unsigned int DCCMetaSurfaceBytes; + unsigned int MacroTileSizeBytes; + unsigned int MacroTileHeight; + unsigned int ExtraDPDEBytesFrame; + unsigned int PDEAndMetaPTEBytesFrame; + unsigned int PixelPTEReqHeightPTEs = 0; + unsigned int HostVMDynamicLevels = 0; + double FractionOfPTEReturnDrop; + + if (GPUVMEnable == true && HostVMEnable == true) { + if (HostVMMinPageSize < 2048) { + HostVMDynamicLevels = HostVMMaxNonCachedPageTableLevels; + } else if (HostVMMinPageSize >= 2048 && HostVMMinPageSize < 1048576) { + HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 1); + } else { + HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 2); + } + } + + *MetaRequestHeight = 8 * BlockHeight256Bytes; + *MetaRequestWidth = 8 * BlockWidth256Bytes; + if (ScanDirection != dm_vert) { + *meta_row_height = *MetaRequestHeight; + *meta_row_width = dml_ceil((double) SwathWidth - 1, *MetaRequestWidth) + *MetaRequestWidth; + *MetaRowByte = *meta_row_width * *MetaRequestHeight * BytePerPixel / 256.0; + } else { + *meta_row_height = *MetaRequestWidth; + *meta_row_width = dml_ceil((double) SwathWidth - 1, *MetaRequestHeight) + *MetaRequestHeight; + *MetaRowByte = *meta_row_width * *MetaRequestWidth * BytePerPixel / 256.0; + } + DCCMetaSurfaceBytes = DCCMetaPitch * (dml_ceil(ViewportHeight - 1, 64 * BlockHeight256Bytes) + 64 * BlockHeight256Bytes) * BytePerPixel / 256; + if (GPUVMEnable == true) { + *MetaPTEBytesFrame = (dml_ceil((double) (DCCMetaSurfaceBytes - 4.0 * 1024.0) / (8 * 4.0 * 1024), 1) + 1) * 64; + MPDEBytesFrame = 128 * (v->GPUVMMaxPageTableLevels - 1); + } else { + *MetaPTEBytesFrame = 0; + MPDEBytesFrame = 0; + } + + if (DCCEnable != true) { + *MetaPTEBytesFrame = 0; + MPDEBytesFrame = 0; + *MetaRowByte = 0; + } + + if (SurfaceTiling == dm_sw_linear) { + MacroTileSizeBytes = 256; + MacroTileHeight = BlockHeight256Bytes; + } else { + MacroTileSizeBytes = 65536; + MacroTileHeight = 16 * BlockHeight256Bytes; + } + *MacroTileWidth = MacroTileSizeBytes / BytePerPixel / MacroTileHeight; + + if (GPUVMEnable == true && v->GPUVMMaxPageTableLevels > 1) { + if (ScanDirection != dm_vert) { + *DPDE0BytesFrame = 64 + * (dml_ceil( + ((Pitch * (dml_ceil(ViewportHeight - 1, MacroTileHeight) + MacroTileHeight) * BytePerPixel) - MacroTileSizeBytes) + / (8 * 2097152), + 1) + 1); + } else { + *DPDE0BytesFrame = 64 + * (dml_ceil( + ((Pitch * (dml_ceil((double) SwathWidth - 1, MacroTileHeight) + MacroTileHeight) * BytePerPixel) - MacroTileSizeBytes) + / (8 * 2097152), + 1) + 1); + } + ExtraDPDEBytesFrame = 128 * (v->GPUVMMaxPageTableLevels - 2); + } else { + *DPDE0BytesFrame = 0; + ExtraDPDEBytesFrame = 0; + } + + PDEAndMetaPTEBytesFrame = *MetaPTEBytesFrame + MPDEBytesFrame + *DPDE0BytesFrame + ExtraDPDEBytesFrame; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: MetaPTEBytesFrame = %d\n", __func__, *MetaPTEBytesFrame); + dml_print("DML::%s: MPDEBytesFrame = %d\n", __func__, MPDEBytesFrame); + dml_print("DML::%s: DPDE0BytesFrame = %d\n", __func__, *DPDE0BytesFrame); + dml_print("DML::%s: ExtraDPDEBytesFrame= %d\n", __func__, ExtraDPDEBytesFrame); + dml_print("DML::%s: PDEAndMetaPTEBytesFrame = %d\n", __func__, PDEAndMetaPTEBytesFrame); +#endif + + if (HostVMEnable == true) { + PDEAndMetaPTEBytesFrame = PDEAndMetaPTEBytesFrame * (1 + 8 * HostVMDynamicLevels); + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: PDEAndMetaPTEBytesFrame = %d\n", __func__, PDEAndMetaPTEBytesFrame); +#endif + + if (SurfaceTiling == dm_sw_linear) { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = 1; + *PixelPTEReqWidth = 32768.0 / BytePerPixel; + *PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } else if (MacroTileSizeBytes == 4096) { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = MacroTileHeight; + *PixelPTEReqWidth = 8 * *MacroTileWidth; + *PTERequestSize = 64; + if (ScanDirection != dm_vert) + FractionOfPTEReturnDrop = 0; + else + FractionOfPTEReturnDrop = 7 / 8; + } else if (GPUVMMinPageSize == 4 && MacroTileSizeBytes > 4096) { + PixelPTEReqHeightPTEs = 16; + *PixelPTEReqHeight = 16 * BlockHeight256Bytes; + *PixelPTEReqWidth = 16 * BlockWidth256Bytes; + *PTERequestSize = 128; + FractionOfPTEReturnDrop = 0; + } else { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = MacroTileHeight; + *PixelPTEReqWidth = 8 * *MacroTileWidth; + *PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } + + if (SurfaceTiling == dm_sw_linear) { + *dpte_row_height = dml_min(128, 1 << (unsigned int) dml_floor(dml_log2(PTEBufferSizeInRequests * *PixelPTEReqWidth / Pitch), 1)); + *dpte_row_width_ub = (dml_ceil((double)(Pitch * *dpte_row_height - 1) / *PixelPTEReqWidth, 1) + 1) * *PixelPTEReqWidth; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqWidth * *PTERequestSize; + } else if (ScanDirection != dm_vert) { + *dpte_row_height = *PixelPTEReqHeight; + *dpte_row_width_ub = (dml_ceil((double) (SwathWidth - 1) / *PixelPTEReqWidth, 1) + 1) * *PixelPTEReqWidth; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqWidth * *PTERequestSize; + } else { + *dpte_row_height = dml_min(*PixelPTEReqWidth, *MacroTileWidth); + *dpte_row_width_ub = (dml_ceil((double) (SwathWidth - 1) / *PixelPTEReqHeight, 1) + 1) * *PixelPTEReqHeight; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqHeight * *PTERequestSize; + } + + if (*PixelPTEBytesPerRow * (1 - FractionOfPTEReturnDrop) <= 64 * PTEBufferSizeInRequests) { + *PTEBufferSizeNotExceeded = true; + } else { + *PTEBufferSizeNotExceeded = false; + } + + if (GPUVMEnable != true) { + *PixelPTEBytesPerRow = 0; + *PTEBufferSizeNotExceeded = true; + } + + dml_print("DML: vm_bytes = meta_pte_bytes_per_frame (per_pipe) = MetaPTEBytesFrame = : %i\n", *MetaPTEBytesFrame); + + if (HostVMEnable == true) { + *PixelPTEBytesPerRow = *PixelPTEBytesPerRow * (1 + 8 * HostVMDynamicLevels); + } + + if (HostVMEnable == true) { + *vm_group_bytes = 512; + *dpte_group_bytes = 512; + } else if (GPUVMEnable == true) { + *vm_group_bytes = 2048; + if (SurfaceTiling != dm_sw_linear && PixelPTEReqHeightPTEs == 1 && ScanDirection == dm_vert) { + *dpte_group_bytes = 512; + } else { + *dpte_group_bytes = 2048; + } + } else { + *vm_group_bytes = 0; + *dpte_group_bytes = 0; + } + return PDEAndMetaPTEBytesFrame; +} + +static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(struct display_mode_lib *mode_lib) +{ + struct vba_vars_st *v = &mode_lib->vba; + unsigned int j, k; + double HostVMInefficiencyFactor = 1.0; + bool NoChromaPlanes = true; + int ReorderBytes; + double VMDataOnlyReturnBW; + double MaxTotalRDBandwidth = 0; + int PrefetchMode = v->PrefetchModePerState[v->VoltageLevel][v->maxMpcComb]; + + v->WritebackDISPCLK = 0.0; + v->DISPCLKWithRamping = 0; + v->DISPCLKWithoutRamping = 0; + v->GlobalDPPCLK = 0.0; + /* DAL custom code: need to update ReturnBW in case min dcfclk is overriden */ + { + double IdealFabricAndSDPPortBandwidthPerState = dml_min( + v->ReturnBusWidth * v->DCFCLKState[v->VoltageLevel][v->maxMpcComb], + v->FabricClockPerState[v->VoltageLevel] * v->FabricDatapathToDCNDataReturn); + double IdealDRAMBandwidthPerState = v->DRAMSpeedPerState[v->VoltageLevel] * v->NumberOfChannels * v->DRAMChannelWidth; + if (v->HostVMEnable != true) { + v->ReturnBW = dml_min( + IdealFabricAndSDPPortBandwidthPerState * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + IdealDRAMBandwidthPerState * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelDataOnly / 100.0); + } else { + v->ReturnBW = dml_min( + IdealFabricAndSDPPortBandwidthPerState * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + IdealDRAMBandwidthPerState * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelMixedWithVMData / 100.0); + } + } + /* End DAL custom code */ + + // DISPCLK and DPPCLK Calculation + // + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->WritebackEnable[k]) { + v->WritebackDISPCLK = dml_max( + v->WritebackDISPCLK, + dml31_CalculateWriteBackDISPCLK( + v->WritebackPixelFormat[k], + v->PixelClock[k], + v->WritebackHRatio[k], + v->WritebackVRatio[k], + v->WritebackHTaps[k], + v->WritebackVTaps[k], + v->WritebackSourceWidth[k], + v->WritebackDestinationWidth[k], + v->HTotal[k], + v->WritebackLineBufferSize)); + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->HRatio[k] > 1) { + v->PSCL_THROUGHPUT_LUMA[k] = dml_min( + v->MaxDCHUBToPSCLThroughput, + v->MaxPSCLToLBThroughput * v->HRatio[k] / dml_ceil(v->htaps[k] / 6.0, 1)); + } else { + v->PSCL_THROUGHPUT_LUMA[k] = dml_min(v->MaxDCHUBToPSCLThroughput, v->MaxPSCLToLBThroughput); + } + + v->DPPCLKUsingSingleDPPLuma = v->PixelClock[k] + * dml_max( + v->vtaps[k] / 6.0 * dml_min(1.0, v->HRatio[k]), + dml_max(v->HRatio[k] * v->VRatio[k] / v->PSCL_THROUGHPUT_LUMA[k], 1.0)); + + if ((v->htaps[k] > 6 || v->vtaps[k] > 6) && v->DPPCLKUsingSingleDPPLuma < 2 * v->PixelClock[k]) { + v->DPPCLKUsingSingleDPPLuma = 2 * v->PixelClock[k]; + } + + if ((v->SourcePixelFormat[k] != dm_420_8 && v->SourcePixelFormat[k] != dm_420_10 && v->SourcePixelFormat[k] != dm_420_12 + && v->SourcePixelFormat[k] != dm_rgbe_alpha)) { + v->PSCL_THROUGHPUT_CHROMA[k] = 0.0; + v->DPPCLKUsingSingleDPP[k] = v->DPPCLKUsingSingleDPPLuma; + } else { + if (v->HRatioChroma[k] > 1) { + v->PSCL_THROUGHPUT_CHROMA[k] = dml_min( + v->MaxDCHUBToPSCLThroughput, + v->MaxPSCLToLBThroughput * v->HRatioChroma[k] / dml_ceil(v->HTAPsChroma[k] / 6.0, 1.0)); + } else { + v->PSCL_THROUGHPUT_CHROMA[k] = dml_min(v->MaxDCHUBToPSCLThroughput, v->MaxPSCLToLBThroughput); + } + v->DPPCLKUsingSingleDPPChroma = v->PixelClock[k] + * dml_max3( + v->VTAPsChroma[k] / 6.0 * dml_min(1.0, v->HRatioChroma[k]), + v->HRatioChroma[k] * v->VRatioChroma[k] / v->PSCL_THROUGHPUT_CHROMA[k], + 1.0); + + if ((v->HTAPsChroma[k] > 6 || v->VTAPsChroma[k] > 6) && v->DPPCLKUsingSingleDPPChroma < 2 * v->PixelClock[k]) { + v->DPPCLKUsingSingleDPPChroma = 2 * v->PixelClock[k]; + } + + v->DPPCLKUsingSingleDPP[k] = dml_max(v->DPPCLKUsingSingleDPPLuma, v->DPPCLKUsingSingleDPPChroma); + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] != k) + continue; + if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_4to1) { + v->DISPCLKWithRamping = dml_max( + v->DISPCLKWithRamping, + v->PixelClock[k] / 4 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100) + * (1 + v->DISPCLKRampingMargin / 100)); + v->DISPCLKWithoutRamping = dml_max( + v->DISPCLKWithoutRamping, + v->PixelClock[k] / 4 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100)); + } else if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_2to1) { + v->DISPCLKWithRamping = dml_max( + v->DISPCLKWithRamping, + v->PixelClock[k] / 2 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100) + * (1 + v->DISPCLKRampingMargin / 100)); + v->DISPCLKWithoutRamping = dml_max( + v->DISPCLKWithoutRamping, + v->PixelClock[k] / 2 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100)); + } else { + v->DISPCLKWithRamping = dml_max( + v->DISPCLKWithRamping, + v->PixelClock[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100) * (1 + v->DISPCLKRampingMargin / 100)); + v->DISPCLKWithoutRamping = dml_max( + v->DISPCLKWithoutRamping, + v->PixelClock[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100)); + } + } + + v->DISPCLKWithRamping = dml_max(v->DISPCLKWithRamping, v->WritebackDISPCLK); + v->DISPCLKWithoutRamping = dml_max(v->DISPCLKWithoutRamping, v->WritebackDISPCLK); + + ASSERT(v->DISPCLKDPPCLKVCOSpeed != 0); + v->DISPCLKWithRampingRoundedToDFSGranularity = RoundToDFSGranularityUp(v->DISPCLKWithRamping, v->DISPCLKDPPCLKVCOSpeed); + v->DISPCLKWithoutRampingRoundedToDFSGranularity = RoundToDFSGranularityUp(v->DISPCLKWithoutRamping, v->DISPCLKDPPCLKVCOSpeed); + v->MaxDispclkRoundedToDFSGranularity = RoundToDFSGranularityDown( + v->soc.clock_limits[v->soc.num_states - 1].dispclk_mhz, + v->DISPCLKDPPCLKVCOSpeed); + if (v->DISPCLKWithoutRampingRoundedToDFSGranularity > v->MaxDispclkRoundedToDFSGranularity) { + v->DISPCLK_calculated = v->DISPCLKWithoutRampingRoundedToDFSGranularity; + } else if (v->DISPCLKWithRampingRoundedToDFSGranularity > v->MaxDispclkRoundedToDFSGranularity) { + v->DISPCLK_calculated = v->MaxDispclkRoundedToDFSGranularity; + } else { + v->DISPCLK_calculated = v->DISPCLKWithRampingRoundedToDFSGranularity; + } + v->DISPCLK = v->DISPCLK_calculated; + DTRACE(" dispclk_mhz (calculated) = %f", v->DISPCLK_calculated); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->DPPCLK_calculated[k] = v->DPPCLKUsingSingleDPP[k] / v->DPPPerPlane[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100); + v->GlobalDPPCLK = dml_max(v->GlobalDPPCLK, v->DPPCLK_calculated[k]); + } + v->GlobalDPPCLK = RoundToDFSGranularityUp(v->GlobalDPPCLK, v->DISPCLKDPPCLKVCOSpeed); + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->DPPCLK_calculated[k] = v->GlobalDPPCLK / 255 * dml_ceil(v->DPPCLK_calculated[k] * 255.0 / v->GlobalDPPCLK, 1); + DTRACE(" dppclk_mhz[%i] (calculated) = %f", k, v->DPPCLK_calculated[k]); + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->DPPCLK[k] = v->DPPCLK_calculated[k]; + } + + // Urgent and B P-State/DRAM Clock Change Watermark + DTRACE(" dcfclk_mhz = %f", v->DCFCLK); + DTRACE(" return_bus_bw = %f", v->ReturnBW); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + CalculateBytePerPixelAnd256BBlockSizes( + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + &v->BytePerPixelY[k], + &v->BytePerPixelC[k], + &v->BytePerPixelDETY[k], + &v->BytePerPixelDETC[k], + &v->BlockHeight256BytesY[k], + &v->BlockHeight256BytesC[k], + &v->BlockWidth256BytesY[k], + &v->BlockWidth256BytesC[k]); + } + + CalculateSwathWidth( + false, + v->NumberOfActivePlanes, + v->SourcePixelFormat, + v->SourceScan, + v->ViewportWidth, + v->ViewportHeight, + v->SurfaceWidthY, + v->SurfaceWidthC, + v->SurfaceHeightY, + v->SurfaceHeightC, + v->ODMCombineEnabled, + v->BytePerPixelY, + v->BytePerPixelC, + v->BlockHeight256BytesY, + v->BlockHeight256BytesC, + v->BlockWidth256BytesY, + v->BlockWidth256BytesC, + v->BlendingAndTiming, + v->HActive, + v->HRatio, + v->DPPPerPlane, + v->SwathWidthSingleDPPY, + v->SwathWidthSingleDPPC, + v->SwathWidthY, + v->SwathWidthC, + v->dummyinteger3, + v->dummyinteger4, + v->swath_width_luma_ub, + v->swath_width_chroma_ub); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->ReadBandwidthPlaneLuma[k] = v->SwathWidthSingleDPPY[k] * v->BytePerPixelY[k] / (v->HTotal[k] / v->PixelClock[k]) + * v->VRatio[k]; + v->ReadBandwidthPlaneChroma[k] = v->SwathWidthSingleDPPC[k] * v->BytePerPixelC[k] / (v->HTotal[k] / v->PixelClock[k]) + * v->VRatioChroma[k]; + DTRACE(" read_bw[%i] = %fBps", k, v->ReadBandwidthPlaneLuma[k] + v->ReadBandwidthPlaneChroma[k]); + } + + // DCFCLK Deep Sleep + CalculateDCFCLKDeepSleep( + mode_lib, + v->NumberOfActivePlanes, + v->BytePerPixelY, + v->BytePerPixelC, + v->VRatio, + v->VRatioChroma, + v->SwathWidthY, + v->SwathWidthC, + v->DPPPerPlane, + v->HRatio, + v->HRatioChroma, + v->PixelClock, + v->PSCL_THROUGHPUT_LUMA, + v->PSCL_THROUGHPUT_CHROMA, + v->DPPCLK, + v->ReadBandwidthPlaneLuma, + v->ReadBandwidthPlaneChroma, + v->ReturnBusWidth, + &v->DCFCLKDeepSleep); + + // DSCCLK + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if ((v->BlendingAndTiming[k] != k) || !v->DSCEnabled[k]) { + v->DSCCLK_calculated[k] = 0.0; + } else { + if (v->OutputFormat[k] == dm_420) + v->DSCFormatFactor = 2; + else if (v->OutputFormat[k] == dm_444) + v->DSCFormatFactor = 1; + else if (v->OutputFormat[k] == dm_n422) + v->DSCFormatFactor = 2; + else + v->DSCFormatFactor = 1; + if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_4to1) + v->DSCCLK_calculated[k] = v->PixelClockBackEnd[k] / 12 / v->DSCFormatFactor + / (1 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100); + else if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_2to1) + v->DSCCLK_calculated[k] = v->PixelClockBackEnd[k] / 6 / v->DSCFormatFactor + / (1 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100); + else + v->DSCCLK_calculated[k] = v->PixelClockBackEnd[k] / 3 / v->DSCFormatFactor + / (1 - v->DISPCLKDPPCLKDSCCLKDownSpreading / 100); + } + } + + // DSC Delay + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + double BPP = v->OutputBpp[k]; + + if (v->DSCEnabled[k] && BPP != 0) { + if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_disabled) { + v->DSCDelay[k] = dscceComputeDelay( + v->DSCInputBitPerComponent[k], + BPP, + dml_ceil((double) v->HActive[k] / v->NumberOfDSCSlices[k], 1), + v->NumberOfDSCSlices[k], + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k]); + } else if (v->ODMCombineEnabled[k] == dm_odm_combine_mode_2to1) { + v->DSCDelay[k] = 2 + * (dscceComputeDelay( + v->DSCInputBitPerComponent[k], + BPP, + dml_ceil((double) v->HActive[k] / v->NumberOfDSCSlices[k], 1), + v->NumberOfDSCSlices[k] / 2.0, + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k])); + } else { + v->DSCDelay[k] = 4 + * (dscceComputeDelay( + v->DSCInputBitPerComponent[k], + BPP, + dml_ceil((double) v->HActive[k] / v->NumberOfDSCSlices[k], 1), + v->NumberOfDSCSlices[k] / 4.0, + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k])); + } + v->DSCDelay[k] = v->DSCDelay[k] * v->PixelClock[k] / v->PixelClockBackEnd[k]; + } else { + v->DSCDelay[k] = 0; + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) + for (j = 0; j < v->NumberOfActivePlanes; ++j) // NumberOfPlanes + if (j != k && v->BlendingAndTiming[k] == j && v->DSCEnabled[j]) + v->DSCDelay[k] = v->DSCDelay[j]; + + // Prefetch + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + unsigned int PDEAndMetaPTEBytesFrameY; + unsigned int PixelPTEBytesPerRowY; + unsigned int MetaRowByteY; + unsigned int MetaRowByteC; + unsigned int PDEAndMetaPTEBytesFrameC; + unsigned int PixelPTEBytesPerRowC; + bool PTEBufferSizeNotExceededY; + bool PTEBufferSizeNotExceededC; + + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_420_12 + || v->SourcePixelFormat[k] == dm_rgbe_alpha) { + if ((v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_420_12) && v->SourceScan[k] != dm_vert) { + v->PTEBufferSizeInRequestsForLuma = (v->PTEBufferSizeInRequestsLuma + v->PTEBufferSizeInRequestsChroma) / 2; + v->PTEBufferSizeInRequestsForChroma = v->PTEBufferSizeInRequestsForLuma; + } else { + v->PTEBufferSizeInRequestsForLuma = v->PTEBufferSizeInRequestsLuma; + v->PTEBufferSizeInRequestsForChroma = v->PTEBufferSizeInRequestsChroma; + } + + PDEAndMetaPTEBytesFrameC = CalculateVMAndRowBytes( + mode_lib, + v->DCCEnable[k], + v->BlockHeight256BytesC[k], + v->BlockWidth256BytesC[k], + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + v->BytePerPixelC[k], + v->SourceScan[k], + v->SwathWidthC[k], + v->ViewportHeightChroma[k], + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMMinPageSize, + v->HostVMMinPageSize, + v->PTEBufferSizeInRequestsForChroma, + v->PitchC[k], + v->DCCMetaPitchC[k], + &v->MacroTileWidthC[k], + &MetaRowByteC, + &PixelPTEBytesPerRowC, + &PTEBufferSizeNotExceededC, + &v->dpte_row_width_chroma_ub[k], + &v->dpte_row_height_chroma[k], + &v->meta_req_width_chroma[k], + &v->meta_req_height_chroma[k], + &v->meta_row_width_chroma[k], + &v->meta_row_height_chroma[k], + &v->dummyinteger1, + &v->dummyinteger2, + &v->PixelPTEReqWidthC[k], + &v->PixelPTEReqHeightC[k], + &v->PTERequestSizeC[k], + &v->dpde0_bytes_per_frame_ub_c[k], + &v->meta_pte_bytes_per_frame_ub_c[k]); + + v->PrefetchSourceLinesC[k] = CalculatePrefetchSourceLines( + mode_lib, + v->VRatioChroma[k], + v->VTAPsChroma[k], + v->Interlace[k], + v->ProgressiveToInterlaceUnitInOPP, + v->SwathHeightC[k], + v->ViewportYStartC[k], + &v->VInitPreFillC[k], + &v->MaxNumSwathC[k]); + } else { + v->PTEBufferSizeInRequestsForLuma = v->PTEBufferSizeInRequestsLuma + v->PTEBufferSizeInRequestsChroma; + v->PTEBufferSizeInRequestsForChroma = 0; + PixelPTEBytesPerRowC = 0; + PDEAndMetaPTEBytesFrameC = 0; + MetaRowByteC = 0; + v->MaxNumSwathC[k] = 0; + v->PrefetchSourceLinesC[k] = 0; + } + + PDEAndMetaPTEBytesFrameY = CalculateVMAndRowBytes( + mode_lib, + v->DCCEnable[k], + v->BlockHeight256BytesY[k], + v->BlockWidth256BytesY[k], + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + v->BytePerPixelY[k], + v->SourceScan[k], + v->SwathWidthY[k], + v->ViewportHeight[k], + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMMinPageSize, + v->HostVMMinPageSize, + v->PTEBufferSizeInRequestsForLuma, + v->PitchY[k], + v->DCCMetaPitchY[k], + &v->MacroTileWidthY[k], + &MetaRowByteY, + &PixelPTEBytesPerRowY, + &PTEBufferSizeNotExceededY, + &v->dpte_row_width_luma_ub[k], + &v->dpte_row_height[k], + &v->meta_req_width[k], + &v->meta_req_height[k], + &v->meta_row_width[k], + &v->meta_row_height[k], + &v->vm_group_bytes[k], + &v->dpte_group_bytes[k], + &v->PixelPTEReqWidthY[k], + &v->PixelPTEReqHeightY[k], + &v->PTERequestSizeY[k], + &v->dpde0_bytes_per_frame_ub_l[k], + &v->meta_pte_bytes_per_frame_ub_l[k]); + + v->PrefetchSourceLinesY[k] = CalculatePrefetchSourceLines( + mode_lib, + v->VRatio[k], + v->vtaps[k], + v->Interlace[k], + v->ProgressiveToInterlaceUnitInOPP, + v->SwathHeightY[k], + v->ViewportYStartY[k], + &v->VInitPreFillY[k], + &v->MaxNumSwathY[k]); + v->PixelPTEBytesPerRow[k] = PixelPTEBytesPerRowY + PixelPTEBytesPerRowC; + v->PDEAndMetaPTEBytesFrame[k] = PDEAndMetaPTEBytesFrameY + PDEAndMetaPTEBytesFrameC; + v->MetaRowByte[k] = MetaRowByteY + MetaRowByteC; + + CalculateRowBandwidth( + v->GPUVMEnable, + v->SourcePixelFormat[k], + v->VRatio[k], + v->VRatioChroma[k], + v->DCCEnable[k], + v->HTotal[k] / v->PixelClock[k], + MetaRowByteY, + MetaRowByteC, + v->meta_row_height[k], + v->meta_row_height_chroma[k], + PixelPTEBytesPerRowY, + PixelPTEBytesPerRowC, + v->dpte_row_height[k], + v->dpte_row_height_chroma[k], + &v->meta_row_bw[k], + &v->dpte_row_bw[k]); + } + + v->TotalDCCActiveDPP = 0; + v->TotalActiveDPP = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->TotalActiveDPP = v->TotalActiveDPP + v->DPPPerPlane[k]; + if (v->DCCEnable[k]) + v->TotalDCCActiveDPP = v->TotalDCCActiveDPP + v->DPPPerPlane[k]; + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_420_12 + || v->SourcePixelFormat[k] == dm_rgbe_alpha) + NoChromaPlanes = false; + } + + ReorderBytes = v->NumberOfChannels + * dml_max3( + v->UrgentOutOfOrderReturnPerChannelPixelDataOnly, + v->UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData, + v->UrgentOutOfOrderReturnPerChannelVMDataOnly); + + VMDataOnlyReturnBW = dml_min( + dml_min(v->ReturnBusWidth * v->DCFCLK, v->FabricClock * v->FabricDatapathToDCNDataReturn) + * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + v->DRAMSpeed * v->NumberOfChannels * v->DRAMChannelWidth + * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly / 100.0); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: v->ReturnBusWidth = %f\n", __func__, v->ReturnBusWidth); + dml_print("DML::%s: v->DCFCLK = %f\n", __func__, v->DCFCLK); + dml_print("DML::%s: v->FabricClock = %f\n", __func__, v->FabricClock); + dml_print("DML::%s: v->FabricDatapathToDCNDataReturn = %f\n", __func__, v->FabricDatapathToDCNDataReturn); + dml_print("DML::%s: v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency = %f\n", __func__, v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency); + dml_print("DML::%s: v->DRAMSpeed = %f\n", __func__, v->DRAMSpeed); + dml_print("DML::%s: v->NumberOfChannels = %f\n", __func__, v->NumberOfChannels); + dml_print("DML::%s: v->DRAMChannelWidth = %f\n", __func__, v->DRAMChannelWidth); + dml_print("DML::%s: v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly = %f\n", __func__, v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly); + dml_print("DML::%s: VMDataOnlyReturnBW = %f\n", __func__, VMDataOnlyReturnBW); + dml_print("DML::%s: ReturnBW = %f\n", __func__, v->ReturnBW); +#endif + + if (v->GPUVMEnable && v->HostVMEnable) + HostVMInefficiencyFactor = v->ReturnBW / VMDataOnlyReturnBW; + + v->UrgentExtraLatency = CalculateExtraLatency( + v->RoundTripPingLatencyCycles, + ReorderBytes, + v->DCFCLK, + v->TotalActiveDPP, + v->PixelChunkSizeInKByte, + v->TotalDCCActiveDPP, + v->MetaChunkSize, + v->ReturnBW, + v->GPUVMEnable, + v->HostVMEnable, + v->NumberOfActivePlanes, + v->DPPPerPlane, + v->dpte_group_bytes, + HostVMInefficiencyFactor, + v->HostVMMinPageSize, + v->HostVMMaxNonCachedPageTableLevels); + + v->TCalc = 24.0 / v->DCFCLKDeepSleep; + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k) { + if (v->WritebackEnable[k] == true) { + v->WritebackDelay[v->VoltageLevel][k] = v->WritebackLatency + + CalculateWriteBackDelay( + v->WritebackPixelFormat[k], + v->WritebackHRatio[k], + v->WritebackVRatio[k], + v->WritebackVTaps[k], + v->WritebackDestinationWidth[k], + v->WritebackDestinationHeight[k], + v->WritebackSourceHeight[k], + v->HTotal[k]) / v->DISPCLK; + } else + v->WritebackDelay[v->VoltageLevel][k] = 0; + for (j = 0; j < v->NumberOfActivePlanes; ++j) { + if (v->BlendingAndTiming[j] == k && v->WritebackEnable[j] == true) { + v->WritebackDelay[v->VoltageLevel][k] = dml_max( + v->WritebackDelay[v->VoltageLevel][k], + v->WritebackLatency + + CalculateWriteBackDelay( + v->WritebackPixelFormat[j], + v->WritebackHRatio[j], + v->WritebackVRatio[j], + v->WritebackVTaps[j], + v->WritebackDestinationWidth[j], + v->WritebackDestinationHeight[j], + v->WritebackSourceHeight[j], + v->HTotal[k]) / v->DISPCLK); + } + } + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) + for (j = 0; j < v->NumberOfActivePlanes; ++j) + if (v->BlendingAndTiming[k] == j) + v->WritebackDelay[v->VoltageLevel][k] = v->WritebackDelay[v->VoltageLevel][j]; + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->MaxVStartupLines[k] = + (v->Interlace[k] && !v->ProgressiveToInterlaceUnitInOPP) ? + dml_floor((v->VTotal[k] - v->VActive[k]) / 2.0, 1.0) : + v->VTotal[k] - v->VActive[k] + - dml_max( + 1.0, + dml_ceil( + (double) v->WritebackDelay[v->VoltageLevel][k] + / (v->HTotal[k] / v->PixelClock[k]), + 1)); + if (v->MaxVStartupLines[k] > 1023) + v->MaxVStartupLines[k] = 1023; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d MaxVStartupLines = %d\n", __func__, k, v->MaxVStartupLines[k]); + dml_print("DML::%s: k=%d VoltageLevel = %d\n", __func__, k, v->VoltageLevel); + dml_print("DML::%s: k=%d WritebackDelay = %f\n", __func__, k, v->WritebackDelay[v->VoltageLevel][k]); +#endif + } + + v->MaximumMaxVStartupLines = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) + v->MaximumMaxVStartupLines = dml_max(v->MaximumMaxVStartupLines, v->MaxVStartupLines[k]); + + // VBA_DELTA + // We don't really care to iterate between the various prefetch modes + //v->PrefetchERROR = CalculateMinAndMaxPrefetchMode(v->AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, &v->MinPrefetchMode, &v->MaxPrefetchMode); + + v->UrgentLatency = CalculateUrgentLatency( + v->UrgentLatencyPixelDataOnly, + v->UrgentLatencyPixelMixedWithVMData, + v->UrgentLatencyVMDataOnly, + v->DoUrgentLatencyAdjustment, + v->UrgentLatencyAdjustmentFabricClockComponent, + v->UrgentLatencyAdjustmentFabricClockReference, + v->FabricClock); + + v->FractionOfUrgentBandwidth = 0.0; + v->FractionOfUrgentBandwidthImmediateFlip = 0.0; + + v->VStartupLines = __DML_VBA_MIN_VSTARTUP__; + + do { + double MaxTotalRDBandwidthNoUrgentBurst = 0.0; + bool DestinationLineTimesForPrefetchLessThan2 = false; + bool VRatioPrefetchMoreThan4 = false; + double TWait = CalculateTWait(PrefetchMode, v->DRAMClockChangeLatency, v->UrgentLatency, v->SREnterPlusExitTime); + MaxTotalRDBandwidth = 0; + + dml_print("DML::%s: Start loop: VStartup = %d\n", __func__, v->VStartupLines); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + Pipe myPipe; + + myPipe.DPPCLK = v->DPPCLK[k]; + myPipe.DISPCLK = v->DISPCLK; + myPipe.PixelClock = v->PixelClock[k]; + myPipe.DCFCLKDeepSleep = v->DCFCLKDeepSleep; + myPipe.DPPPerPlane = v->DPPPerPlane[k]; + myPipe.ScalerEnabled = v->ScalerEnabled[k]; + myPipe.SourceScan = v->SourceScan[k]; + myPipe.BlockWidth256BytesY = v->BlockWidth256BytesY[k]; + myPipe.BlockHeight256BytesY = v->BlockHeight256BytesY[k]; + myPipe.BlockWidth256BytesC = v->BlockWidth256BytesC[k]; + myPipe.BlockHeight256BytesC = v->BlockHeight256BytesC[k]; + myPipe.InterlaceEnable = v->Interlace[k]; + myPipe.NumberOfCursors = v->NumberOfCursors[k]; + myPipe.VBlank = v->VTotal[k] - v->VActive[k]; + myPipe.HTotal = v->HTotal[k]; + myPipe.DCCEnable = v->DCCEnable[k]; + myPipe.ODMCombineIsEnabled = v->ODMCombineEnabled[k] == dm_odm_combine_mode_4to1 + || v->ODMCombineEnabled[k] == dm_odm_combine_mode_2to1; + myPipe.SourcePixelFormat = v->SourcePixelFormat[k]; + myPipe.BytePerPixelY = v->BytePerPixelY[k]; + myPipe.BytePerPixelC = v->BytePerPixelC[k]; + myPipe.ProgressiveToInterlaceUnitInOPP = v->ProgressiveToInterlaceUnitInOPP; + v->ErrorResult[k] = CalculatePrefetchSchedule( + mode_lib, + HostVMInefficiencyFactor, + &myPipe, + v->DSCDelay[k], + v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater, + v->DPPCLKDelaySCL, + v->DPPCLKDelaySCLLBOnly, + v->DPPCLKDelayCNVCCursor, + v->DISPCLKDelaySubtotal, + (unsigned int) (v->SwathWidthY[k] / v->HRatio[k]), + v->OutputFormat[k], + v->MaxInterDCNTileRepeaters, + dml_min(v->VStartupLines, v->MaxVStartupLines[k]), + v->MaxVStartupLines[k], + v->GPUVMMaxPageTableLevels, + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->HostVMMinPageSize, + v->DynamicMetadataEnable[k], + v->DynamicMetadataVMEnabled, + v->DynamicMetadataLinesBeforeActiveRequired[k], + v->DynamicMetadataTransmittedBytes[k], + v->UrgentLatency, + v->UrgentExtraLatency, + v->TCalc, + v->PDEAndMetaPTEBytesFrame[k], + v->MetaRowByte[k], + v->PixelPTEBytesPerRow[k], + v->PrefetchSourceLinesY[k], + v->SwathWidthY[k], + v->VInitPreFillY[k], + v->MaxNumSwathY[k], + v->PrefetchSourceLinesC[k], + v->SwathWidthC[k], + v->VInitPreFillC[k], + v->MaxNumSwathC[k], + v->swath_width_luma_ub[k], + v->swath_width_chroma_ub[k], + v->SwathHeightY[k], + v->SwathHeightC[k], + TWait, + &v->DSTXAfterScaler[k], + &v->DSTYAfterScaler[k], + &v->DestinationLinesForPrefetch[k], + &v->PrefetchBandwidth[k], + &v->DestinationLinesToRequestVMInVBlank[k], + &v->DestinationLinesToRequestRowInVBlank[k], + &v->VRatioPrefetchY[k], + &v->VRatioPrefetchC[k], + &v->RequiredPrefetchPixDataBWLuma[k], + &v->RequiredPrefetchPixDataBWChroma[k], + &v->NotEnoughTimeForDynamicMetadata[k], + &v->Tno_bw[k], + &v->prefetch_vmrow_bw[k], + &v->Tdmdl_vm[k], + &v->Tdmdl[k], + &v->TSetup[k], + &v->VUpdateOffsetPix[k], + &v->VUpdateWidthPix[k], + &v->VReadyOffsetPix[k]); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%0d Prefetch cal result=%0d\n", __func__, k, v->ErrorResult[k]); +#endif + v->VStartup[k] = dml_min(v->VStartupLines, v->MaxVStartupLines[k]); + } + + v->NoEnoughUrgentLatencyHiding = false; + v->NoEnoughUrgentLatencyHidingPre = false; + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->cursor_bw[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k]; + v->cursor_bw_pre[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatioPrefetchY[k]; + + CalculateUrgentBurstFactor( + v->swath_width_luma_ub[k], + v->swath_width_chroma_ub[k], + v->SwathHeightY[k], + v->SwathHeightC[k], + v->HTotal[k] / v->PixelClock[k], + v->UrgentLatency, + v->CursorBufferSize, + v->CursorWidth[k][0], + v->CursorBPP[k][0], + v->VRatio[k], + v->VRatioChroma[k], + v->BytePerPixelDETY[k], + v->BytePerPixelDETC[k], + v->DETBufferSizeY[k], + v->DETBufferSizeC[k], + &v->UrgBurstFactorCursor[k], + &v->UrgBurstFactorLuma[k], + &v->UrgBurstFactorChroma[k], + &v->NoUrgentLatencyHiding[k]); + + CalculateUrgentBurstFactor( + v->swath_width_luma_ub[k], + v->swath_width_chroma_ub[k], + v->SwathHeightY[k], + v->SwathHeightC[k], + v->HTotal[k] / v->PixelClock[k], + v->UrgentLatency, + v->CursorBufferSize, + v->CursorWidth[k][0], + v->CursorBPP[k][0], + v->VRatioPrefetchY[k], + v->VRatioPrefetchC[k], + v->BytePerPixelDETY[k], + v->BytePerPixelDETC[k], + v->DETBufferSizeY[k], + v->DETBufferSizeC[k], + &v->UrgBurstFactorCursorPre[k], + &v->UrgBurstFactorLumaPre[k], + &v->UrgBurstFactorChromaPre[k], + &v->NoUrgentLatencyHidingPre[k]); + + MaxTotalRDBandwidth = MaxTotalRDBandwidth + + dml_max3( + v->DPPPerPlane[k] * v->prefetch_vmrow_bw[k], + v->ReadBandwidthPlaneLuma[k] * v->UrgBurstFactorLuma[k] + + v->ReadBandwidthPlaneChroma[k] * v->UrgBurstFactorChroma[k] + + v->cursor_bw[k] * v->UrgBurstFactorCursor[k] + + v->DPPPerPlane[k] * (v->meta_row_bw[k] + v->dpte_row_bw[k]), + v->DPPPerPlane[k] + * (v->RequiredPrefetchPixDataBWLuma[k] * v->UrgBurstFactorLumaPre[k] + + v->RequiredPrefetchPixDataBWChroma[k] * v->UrgBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgBurstFactorCursorPre[k]); + + MaxTotalRDBandwidthNoUrgentBurst = MaxTotalRDBandwidthNoUrgentBurst + + dml_max3( + v->DPPPerPlane[k] * v->prefetch_vmrow_bw[k], + v->ReadBandwidthPlaneLuma[k] + v->ReadBandwidthPlaneChroma[k] + v->cursor_bw[k] + + v->DPPPerPlane[k] * (v->meta_row_bw[k] + v->dpte_row_bw[k]), + v->DPPPerPlane[k] * (v->RequiredPrefetchPixDataBWLuma[k] + v->RequiredPrefetchPixDataBWChroma[k]) + + v->cursor_bw_pre[k]); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%0d DPPPerPlane=%d\n", __func__, k, v->DPPPerPlane[k]); + dml_print("DML::%s: k=%0d UrgBurstFactorLuma=%f\n", __func__, k, v->UrgBurstFactorLuma[k]); + dml_print("DML::%s: k=%0d UrgBurstFactorChroma=%f\n", __func__, k, v->UrgBurstFactorChroma[k]); + dml_print("DML::%s: k=%0d UrgBurstFactorLumaPre=%f\n", __func__, k, v->UrgBurstFactorLumaPre[k]); + dml_print("DML::%s: k=%0d UrgBurstFactorChromaPre=%f\n", __func__, k, v->UrgBurstFactorChromaPre[k]); + + dml_print("DML::%s: k=%0d VRatioPrefetchY=%f\n", __func__, k, v->VRatioPrefetchY[k]); + dml_print("DML::%s: k=%0d VRatioY=%f\n", __func__, k, v->VRatio[k]); + + dml_print("DML::%s: k=%0d prefetch_vmrow_bw=%f\n", __func__, k, v->prefetch_vmrow_bw[k]); + dml_print("DML::%s: k=%0d ReadBandwidthPlaneLuma=%f\n", __func__, k, v->ReadBandwidthPlaneLuma[k]); + dml_print("DML::%s: k=%0d ReadBandwidthPlaneChroma=%f\n", __func__, k, v->ReadBandwidthPlaneChroma[k]); + dml_print("DML::%s: k=%0d cursor_bw=%f\n", __func__, k, v->cursor_bw[k]); + dml_print("DML::%s: k=%0d meta_row_bw=%f\n", __func__, k, v->meta_row_bw[k]); + dml_print("DML::%s: k=%0d dpte_row_bw=%f\n", __func__, k, v->dpte_row_bw[k]); + dml_print("DML::%s: k=%0d RequiredPrefetchPixDataBWLuma=%f\n", __func__, k, v->RequiredPrefetchPixDataBWLuma[k]); + dml_print("DML::%s: k=%0d RequiredPrefetchPixDataBWChroma=%f\n", __func__, k, v->RequiredPrefetchPixDataBWChroma[k]); + dml_print("DML::%s: k=%0d cursor_bw_pre=%f\n", __func__, k, v->cursor_bw_pre[k]); + dml_print("DML::%s: k=%0d MaxTotalRDBandwidthNoUrgentBurst=%f\n", __func__, k, MaxTotalRDBandwidthNoUrgentBurst); +#endif + + if (v->DestinationLinesForPrefetch[k] < 2) + DestinationLineTimesForPrefetchLessThan2 = true; + + if (v->VRatioPrefetchY[k] > 4 || v->VRatioPrefetchC[k] > 4) + VRatioPrefetchMoreThan4 = true; + + if (v->NoUrgentLatencyHiding[k] == true) + v->NoEnoughUrgentLatencyHiding = true; + + if (v->NoUrgentLatencyHidingPre[k] == true) + v->NoEnoughUrgentLatencyHidingPre = true; + } + + v->FractionOfUrgentBandwidth = MaxTotalRDBandwidthNoUrgentBurst / v->ReturnBW; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: MaxTotalRDBandwidthNoUrgentBurst=%f \n", __func__, MaxTotalRDBandwidthNoUrgentBurst); + dml_print("DML::%s: ReturnBW=%f \n", __func__, v->ReturnBW); + dml_print("DML::%s: FractionOfUrgentBandwidth=%f \n", __func__, v->FractionOfUrgentBandwidth); +#endif + + if (MaxTotalRDBandwidth <= v->ReturnBW && v->NoEnoughUrgentLatencyHiding == 0 && v->NoEnoughUrgentLatencyHidingPre == 0 + && !VRatioPrefetchMoreThan4 && !DestinationLineTimesForPrefetchLessThan2) + v->PrefetchModeSupported = true; + else { + v->PrefetchModeSupported = false; + dml_print("DML::%s: ***failed***. Bandwidth violation. Results are NOT valid\n", __func__); + dml_print("DML::%s: MaxTotalRDBandwidth:%f AvailReturnBandwidth:%f\n", __func__, MaxTotalRDBandwidth, v->ReturnBW); + dml_print("DML::%s: VRatioPrefetch %s more than 4\n", __func__, (VRatioPrefetchMoreThan4) ? "is" : "is not"); + dml_print("DML::%s: DestinationLines for Prefetch %s less than 2\n", __func__, (DestinationLineTimesForPrefetchLessThan2) ? "is" : "is not"); + } + + // PREVIOUS_ERROR + // This error result check was done after the PrefetchModeSupported. So we will + // still try to calculate flip schedule even prefetch mode not supported + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->ErrorResult[k] == true || v->NotEnoughTimeForDynamicMetadata[k] == true) { + v->PrefetchModeSupported = false; + dml_print("DML::%s: ***failed***. Prefetch schedule violation. Results are NOT valid\n", __func__); + } + } + + if (v->PrefetchModeSupported == true && v->ImmediateFlipSupport == true) { + v->BandwidthAvailableForImmediateFlip = v->ReturnBW; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->BandwidthAvailableForImmediateFlip = v->BandwidthAvailableForImmediateFlip + - dml_max( + v->ReadBandwidthPlaneLuma[k] * v->UrgBurstFactorLuma[k] + + v->ReadBandwidthPlaneChroma[k] * v->UrgBurstFactorChroma[k] + + v->cursor_bw[k] * v->UrgBurstFactorCursor[k], + v->DPPPerPlane[k] + * (v->RequiredPrefetchPixDataBWLuma[k] * v->UrgBurstFactorLumaPre[k] + + v->RequiredPrefetchPixDataBWChroma[k] * v->UrgBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgBurstFactorCursorPre[k]); + } + + v->TotImmediateFlipBytes = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->TotImmediateFlipBytes = v->TotImmediateFlipBytes + + v->DPPPerPlane[k] * (v->PDEAndMetaPTEBytesFrame[k] + v->MetaRowByte[k] + v->PixelPTEBytesPerRow[k]); + } + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + CalculateFlipSchedule( + mode_lib, + HostVMInefficiencyFactor, + v->UrgentExtraLatency, + v->UrgentLatency, + v->GPUVMMaxPageTableLevels, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMEnable, + v->HostVMMinPageSize, + v->PDEAndMetaPTEBytesFrame[k], + v->MetaRowByte[k], + v->PixelPTEBytesPerRow[k], + v->BandwidthAvailableForImmediateFlip, + v->TotImmediateFlipBytes, + v->SourcePixelFormat[k], + v->HTotal[k] / v->PixelClock[k], + v->VRatio[k], + v->VRatioChroma[k], + v->Tno_bw[k], + v->DCCEnable[k], + v->dpte_row_height[k], + v->meta_row_height[k], + v->dpte_row_height_chroma[k], + v->meta_row_height_chroma[k], + &v->DestinationLinesToRequestVMInImmediateFlip[k], + &v->DestinationLinesToRequestRowInImmediateFlip[k], + &v->final_flip_bw[k], + &v->ImmediateFlipSupportedForPipe[k]); + } + + v->total_dcn_read_bw_with_flip = 0.0; + v->total_dcn_read_bw_with_flip_no_urgent_burst = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->total_dcn_read_bw_with_flip = v->total_dcn_read_bw_with_flip + + dml_max3( + v->DPPPerPlane[k] * v->prefetch_vmrow_bw[k], + v->DPPPerPlane[k] * v->final_flip_bw[k] + + v->ReadBandwidthLuma[k] * v->UrgBurstFactorLuma[k] + + v->ReadBandwidthChroma[k] * v->UrgBurstFactorChroma[k] + + v->cursor_bw[k] * v->UrgBurstFactorCursor[k], + v->DPPPerPlane[k] + * (v->final_flip_bw[k] + + v->RequiredPrefetchPixDataBWLuma[k] * v->UrgBurstFactorLumaPre[k] + + v->RequiredPrefetchPixDataBWChroma[k] * v->UrgBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgBurstFactorCursorPre[k]); + v->total_dcn_read_bw_with_flip_no_urgent_burst = v->total_dcn_read_bw_with_flip_no_urgent_burst + + dml_max3( + v->DPPPerPlane[k] * v->prefetch_vmrow_bw[k], + v->DPPPerPlane[k] * v->final_flip_bw[k] + v->ReadBandwidthPlaneLuma[k] + + v->ReadBandwidthPlaneChroma[k] + v->cursor_bw[k], + v->DPPPerPlane[k] + * (v->final_flip_bw[k] + v->RequiredPrefetchPixDataBWLuma[k] + + v->RequiredPrefetchPixDataBWChroma[k]) + v->cursor_bw_pre[k]); + } + v->FractionOfUrgentBandwidthImmediateFlip = v->total_dcn_read_bw_with_flip_no_urgent_burst / v->ReturnBW; + + v->ImmediateFlipSupported = true; + if (v->total_dcn_read_bw_with_flip > v->ReturnBW) { +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: total_dcn_read_bw_with_flip %f (bw w/ flip too high!)\n", __func__, v->total_dcn_read_bw_with_flip); +#endif + v->ImmediateFlipSupported = false; + v->total_dcn_read_bw_with_flip = MaxTotalRDBandwidth; + } + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->ImmediateFlipSupportedForPipe[k] == false) { +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Pipe %0d not supporting iflip\n", + __func__, k); +#endif + v->ImmediateFlipSupported = false; + } + } + } else { + v->ImmediateFlipSupported = false; + } + + v->PrefetchAndImmediateFlipSupported = + (v->PrefetchModeSupported == true + && ((!v->ImmediateFlipSupport && !v->HostVMEnable + && v->ImmediateFlipRequirement != dm_immediate_flip_required) || v->ImmediateFlipSupported)) ? + true : false; +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: PrefetchModeSupported %d\n", __func__, v->PrefetchModeSupported); + dml_print("DML::%s: ImmediateFlipRequirement %d\n", __func__, v->ImmediateFlipRequirement == dm_immediate_flip_required); + dml_print("DML::%s: ImmediateFlipSupported %d\n", __func__, v->ImmediateFlipSupported); + dml_print("DML::%s: ImmediateFlipSupport %d\n", __func__, v->ImmediateFlipSupport); + dml_print("DML::%s: HostVMEnable %d\n", __func__, v->HostVMEnable); + dml_print("DML::%s: PrefetchAndImmediateFlipSupported %d\n", __func__, v->PrefetchAndImmediateFlipSupported); +#endif + dml_print("DML::%s: Done loop: Vstartup=%d, Max Vstartup is %d\n", __func__, v->VStartupLines, v->MaximumMaxVStartupLines); + + v->VStartupLines = v->VStartupLines + 1; + } while (!v->PrefetchAndImmediateFlipSupported && v->VStartupLines <= v->MaximumMaxVStartupLines); + ASSERT(v->PrefetchAndImmediateFlipSupported); + + // Unbounded Request Enabled + CalculateUnboundedRequestAndCompressedBufferSize( + v->DETBufferSizeInKByte[0], + v->ConfigReturnBufferSizeInKByte, + v->UseUnboundedRequesting, + v->TotalActiveDPP, + NoChromaPlanes, + v->MaxNumDPP, + v->CompressedBufferSegmentSizeInkByte, + v->Output, + &v->UnboundedRequestEnabled, + &v->CompressedBufferSizeInkByte); + + //Watermarks and NB P-State/DRAM Clock Change Support + { + enum clock_change_support DRAMClockChangeSupport; // dummy + CalculateWatermarksAndDRAMSpeedChangeSupport( + mode_lib, + PrefetchMode, + v->NumberOfActivePlanes, + v->MaxLineBufferLines, + v->LineBufferSize, + v->WritebackInterfaceBufferSize, + v->DCFCLK, + v->ReturnBW, + v->SynchronizedVBlank, + v->dpte_group_bytes, + v->MetaChunkSize, + v->UrgentLatency, + v->UrgentExtraLatency, + v->WritebackLatency, + v->WritebackChunkSize, + v->SOCCLK, + v->DRAMClockChangeLatency, + v->SRExitTime, + v->SREnterPlusExitTime, + v->SRExitZ8Time, + v->SREnterPlusExitZ8Time, + v->DCFCLKDeepSleep, + v->DETBufferSizeY, + v->DETBufferSizeC, + v->SwathHeightY, + v->SwathHeightC, + v->LBBitPerPixel, + v->SwathWidthY, + v->SwathWidthC, + v->HRatio, + v->HRatioChroma, + v->vtaps, + v->VTAPsChroma, + v->VRatio, + v->VRatioChroma, + v->HTotal, + v->PixelClock, + v->BlendingAndTiming, + v->DPPPerPlane, + v->BytePerPixelDETY, + v->BytePerPixelDETC, + v->DSTXAfterScaler, + v->DSTYAfterScaler, + v->WritebackEnable, + v->WritebackPixelFormat, + v->WritebackDestinationWidth, + v->WritebackDestinationHeight, + v->WritebackSourceHeight, + v->UnboundedRequestEnabled, + v->CompressedBufferSizeInkByte, + &DRAMClockChangeSupport, + &v->UrgentWatermark, + &v->WritebackUrgentWatermark, + &v->DRAMClockChangeWatermark, + &v->WritebackDRAMClockChangeWatermark, + &v->StutterExitWatermark, + &v->StutterEnterPlusExitWatermark, + &v->Z8StutterExitWatermark, + &v->Z8StutterEnterPlusExitWatermark, + &v->MinActiveDRAMClockChangeLatencySupported); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->WritebackEnable[k] == true) { + v->WritebackAllowDRAMClockChangeEndPosition[k] = dml_max( + 0, + v->VStartup[k] * v->HTotal[k] / v->PixelClock[k] - v->WritebackDRAMClockChangeWatermark); + } else { + v->WritebackAllowDRAMClockChangeEndPosition[k] = 0; + } + } + } + + //Display Pipeline Delivery Time in Prefetch, Groups + CalculatePixelDeliveryTimes( + v->NumberOfActivePlanes, + v->VRatio, + v->VRatioChroma, + v->VRatioPrefetchY, + v->VRatioPrefetchC, + v->swath_width_luma_ub, + v->swath_width_chroma_ub, + v->DPPPerPlane, + v->HRatio, + v->HRatioChroma, + v->PixelClock, + v->PSCL_THROUGHPUT_LUMA, + v->PSCL_THROUGHPUT_CHROMA, + v->DPPCLK, + v->BytePerPixelC, + v->SourceScan, + v->NumberOfCursors, + v->CursorWidth, + v->CursorBPP, + v->BlockWidth256BytesY, + v->BlockHeight256BytesY, + v->BlockWidth256BytesC, + v->BlockHeight256BytesC, + v->DisplayPipeLineDeliveryTimeLuma, + v->DisplayPipeLineDeliveryTimeChroma, + v->DisplayPipeLineDeliveryTimeLumaPrefetch, + v->DisplayPipeLineDeliveryTimeChromaPrefetch, + v->DisplayPipeRequestDeliveryTimeLuma, + v->DisplayPipeRequestDeliveryTimeChroma, + v->DisplayPipeRequestDeliveryTimeLumaPrefetch, + v->DisplayPipeRequestDeliveryTimeChromaPrefetch, + v->CursorRequestDeliveryTime, + v->CursorRequestDeliveryTimePrefetch); + + CalculateMetaAndPTETimes( + v->NumberOfActivePlanes, + v->GPUVMEnable, + v->MetaChunkSize, + v->MinMetaChunkSizeBytes, + v->HTotal, + v->VRatio, + v->VRatioChroma, + v->DestinationLinesToRequestRowInVBlank, + v->DestinationLinesToRequestRowInImmediateFlip, + v->DCCEnable, + v->PixelClock, + v->BytePerPixelY, + v->BytePerPixelC, + v->SourceScan, + v->dpte_row_height, + v->dpte_row_height_chroma, + v->meta_row_width, + v->meta_row_width_chroma, + v->meta_row_height, + v->meta_row_height_chroma, + v->meta_req_width, + v->meta_req_width_chroma, + v->meta_req_height, + v->meta_req_height_chroma, + v->dpte_group_bytes, + v->PTERequestSizeY, + v->PTERequestSizeC, + v->PixelPTEReqWidthY, + v->PixelPTEReqHeightY, + v->PixelPTEReqWidthC, + v->PixelPTEReqHeightC, + v->dpte_row_width_luma_ub, + v->dpte_row_width_chroma_ub, + v->DST_Y_PER_PTE_ROW_NOM_L, + v->DST_Y_PER_PTE_ROW_NOM_C, + v->DST_Y_PER_META_ROW_NOM_L, + v->DST_Y_PER_META_ROW_NOM_C, + v->TimePerMetaChunkNominal, + v->TimePerChromaMetaChunkNominal, + v->TimePerMetaChunkVBlank, + v->TimePerChromaMetaChunkVBlank, + v->TimePerMetaChunkFlip, + v->TimePerChromaMetaChunkFlip, + v->time_per_pte_group_nom_luma, + v->time_per_pte_group_vblank_luma, + v->time_per_pte_group_flip_luma, + v->time_per_pte_group_nom_chroma, + v->time_per_pte_group_vblank_chroma, + v->time_per_pte_group_flip_chroma); + + CalculateVMGroupAndRequestTimes( + v->NumberOfActivePlanes, + v->GPUVMEnable, + v->GPUVMMaxPageTableLevels, + v->HTotal, + v->BytePerPixelC, + v->DestinationLinesToRequestVMInVBlank, + v->DestinationLinesToRequestVMInImmediateFlip, + v->DCCEnable, + v->PixelClock, + v->dpte_row_width_luma_ub, + v->dpte_row_width_chroma_ub, + v->vm_group_bytes, + v->dpde0_bytes_per_frame_ub_l, + v->dpde0_bytes_per_frame_ub_c, + v->meta_pte_bytes_per_frame_ub_l, + v->meta_pte_bytes_per_frame_ub_c, + v->TimePerVMGroupVBlank, + v->TimePerVMGroupFlip, + v->TimePerVMRequestVBlank, + v->TimePerVMRequestFlip); + + // Min TTUVBlank + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (PrefetchMode == 0) { + v->AllowDRAMClockChangeDuringVBlank[k] = true; + v->AllowDRAMSelfRefreshDuringVBlank[k] = true; + v->MinTTUVBlank[k] = dml_max( + v->DRAMClockChangeWatermark, + dml_max(v->StutterEnterPlusExitWatermark, v->UrgentWatermark)); + } else if (PrefetchMode == 1) { + v->AllowDRAMClockChangeDuringVBlank[k] = false; + v->AllowDRAMSelfRefreshDuringVBlank[k] = true; + v->MinTTUVBlank[k] = dml_max(v->StutterEnterPlusExitWatermark, v->UrgentWatermark); + } else { + v->AllowDRAMClockChangeDuringVBlank[k] = false; + v->AllowDRAMSelfRefreshDuringVBlank[k] = false; + v->MinTTUVBlank[k] = v->UrgentWatermark; + } + if (!v->DynamicMetadataEnable[k]) + v->MinTTUVBlank[k] = v->TCalc + v->MinTTUVBlank[k]; + } + + // DCC Configuration + v->ActiveDPPs = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + CalculateDCCConfiguration(v->DCCEnable[k], false, // We should always know the direction DCCProgrammingAssumesScanDirectionUnknown, + v->SourcePixelFormat[k], + v->SurfaceWidthY[k], + v->SurfaceWidthC[k], + v->SurfaceHeightY[k], + v->SurfaceHeightC[k], + v->DETBufferSizeInKByte[0] * 1024, + v->BlockHeight256BytesY[k], + v->BlockHeight256BytesC[k], + v->SurfaceTiling[k], + v->BytePerPixelY[k], + v->BytePerPixelC[k], + v->BytePerPixelDETY[k], + v->BytePerPixelDETC[k], + v->SourceScan[k], + &v->DCCYMaxUncompressedBlock[k], + &v->DCCCMaxUncompressedBlock[k], + &v->DCCYMaxCompressedBlock[k], + &v->DCCCMaxCompressedBlock[k], + &v->DCCYIndependentBlock[k], + &v->DCCCIndependentBlock[k]); + } + + // VStartup Adjustment + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + bool isInterlaceTiming; + double Tvstartup_margin = (v->MaxVStartupLines[k] - v->VStartup[k]) * v->HTotal[k] / v->PixelClock[k]; +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d, MinTTUVBlank = %f (before margin)\n", __func__, k, v->MinTTUVBlank[k]); +#endif + + v->MinTTUVBlank[k] = v->MinTTUVBlank[k] + Tvstartup_margin; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d, Tvstartup_margin = %f\n", __func__, k, Tvstartup_margin); + dml_print("DML::%s: k=%d, MaxVStartupLines = %d\n", __func__, k, v->MaxVStartupLines[k]); + dml_print("DML::%s: k=%d, VStartup = %d\n", __func__, k, v->VStartup[k]); + dml_print("DML::%s: k=%d, MinTTUVBlank = %f\n", __func__, k, v->MinTTUVBlank[k]); +#endif + + v->Tdmdl[k] = v->Tdmdl[k] + Tvstartup_margin; + if (v->DynamicMetadataEnable[k] && v->DynamicMetadataVMEnabled) { + v->Tdmdl_vm[k] = v->Tdmdl_vm[k] + Tvstartup_margin; + } + + isInterlaceTiming = (v->Interlace[k] && !v->ProgressiveToInterlaceUnitInOPP); + + v->MIN_DST_Y_NEXT_START[k] = ((isInterlaceTiming ? dml_floor((v->VTotal[k] - v->VFrontPorch[k]) / 2.0, 1.0) : v->VTotal[k]) + - v->VFrontPorch[k]) + + dml_max(1.0, dml_ceil(v->WritebackDelay[v->VoltageLevel][k] / (v->HTotal[k] / v->PixelClock[k]), 1.0)) + + dml_floor(4.0 * v->TSetup[k] / (v->HTotal[k] / v->PixelClock[k]), 1.0) / 4.0; + + v->VStartup[k] = (isInterlaceTiming ? (2 * v->MaxVStartupLines[k]) : v->MaxVStartupLines[k]); + + if (((v->VUpdateOffsetPix[k] + v->VUpdateWidthPix[k] + v->VReadyOffsetPix[k]) / v->HTotal[k]) + <= (isInterlaceTiming ? + dml_floor((v->VTotal[k] - v->VActive[k] - v->VFrontPorch[k] - v->VStartup[k]) / 2.0, 1.0) : + (int) (v->VTotal[k] - v->VActive[k] - v->VFrontPorch[k] - v->VStartup[k]))) { + v->VREADY_AT_OR_AFTER_VSYNC[k] = true; + } else { + v->VREADY_AT_OR_AFTER_VSYNC[k] = false; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d, VStartup = %d (max)\n", __func__, k, v->VStartup[k]); + dml_print("DML::%s: k=%d, VUpdateOffsetPix = %d\n", __func__, k, v->VUpdateOffsetPix[k]); + dml_print("DML::%s: k=%d, VUpdateWidthPix = %d\n", __func__, k, v->VUpdateWidthPix[k]); + dml_print("DML::%s: k=%d, VReadyOffsetPix = %d\n", __func__, k, v->VReadyOffsetPix[k]); + dml_print("DML::%s: k=%d, HTotal = %d\n", __func__, k, v->HTotal[k]); + dml_print("DML::%s: k=%d, VTotal = %d\n", __func__, k, v->VTotal[k]); + dml_print("DML::%s: k=%d, VActive = %d\n", __func__, k, v->VActive[k]); + dml_print("DML::%s: k=%d, VFrontPorch = %d\n", __func__, k, v->VFrontPorch[k]); + dml_print("DML::%s: k=%d, VStartup = %d\n", __func__, k, v->VStartup[k]); + dml_print("DML::%s: k=%d, MIN_DST_Y_NEXT_START = %f\n", __func__, k, v->MIN_DST_Y_NEXT_START[k]); + dml_print("DML::%s: k=%d, VREADY_AT_OR_AFTER_VSYNC = %d\n", __func__, k, v->VREADY_AT_OR_AFTER_VSYNC[k]); +#endif + } + + { + //Maximum Bandwidth Used + double TotalWRBandwidth = 0; + double MaxPerPlaneVActiveWRBandwidth = 0; + double WRBandwidth = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->WritebackEnable[k] == true && v->WritebackPixelFormat[k] == dm_444_32) { + WRBandwidth = v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] + / (v->HTotal[k] * v->WritebackSourceHeight[k] / v->PixelClock[k]) * 4; + } else if (v->WritebackEnable[k] == true) { + WRBandwidth = v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] + / (v->HTotal[k] * v->WritebackSourceHeight[k] / v->PixelClock[k]) * 8; + } + TotalWRBandwidth = TotalWRBandwidth + WRBandwidth; + MaxPerPlaneVActiveWRBandwidth = dml_max(MaxPerPlaneVActiveWRBandwidth, WRBandwidth); + } + + v->TotalDataReadBandwidth = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->TotalDataReadBandwidth = v->TotalDataReadBandwidth + v->ReadBandwidthPlaneLuma[k] + v->ReadBandwidthPlaneChroma[k]; + } + } + // Stutter Efficiency + CalculateStutterEfficiency( + mode_lib, + v->CompressedBufferSizeInkByte, + v->UnboundedRequestEnabled, + v->ConfigReturnBufferSizeInKByte, + v->MetaFIFOSizeInKEntries, + v->ZeroSizeBufferEntries, + v->NumberOfActivePlanes, + v->ROBBufferSizeInKByte, + v->TotalDataReadBandwidth, + v->DCFCLK, + v->ReturnBW, + v->COMPBUF_RESERVED_SPACE_64B, + v->COMPBUF_RESERVED_SPACE_ZS, + v->SRExitTime, + v->SRExitZ8Time, + v->SynchronizedVBlank, + v->StutterEnterPlusExitWatermark, + v->Z8StutterEnterPlusExitWatermark, + v->ProgressiveToInterlaceUnitInOPP, + v->Interlace, + v->MinTTUVBlank, + v->DPPPerPlane, + v->DETBufferSizeY, + v->BytePerPixelY, + v->BytePerPixelDETY, + v->SwathWidthY, + v->SwathHeightY, + v->SwathHeightC, + v->DCCRateLuma, + v->DCCRateChroma, + v->DCCFractionOfZeroSizeRequestsLuma, + v->DCCFractionOfZeroSizeRequestsChroma, + v->HTotal, + v->VTotal, + v->PixelClock, + v->VRatio, + v->SourceScan, + v->BlockHeight256BytesY, + v->BlockWidth256BytesY, + v->BlockHeight256BytesC, + v->BlockWidth256BytesC, + v->DCCYMaxUncompressedBlock, + v->DCCCMaxUncompressedBlock, + v->VActive, + v->DCCEnable, + v->WritebackEnable, + v->ReadBandwidthPlaneLuma, + v->ReadBandwidthPlaneChroma, + v->meta_row_bw, + v->dpte_row_bw, + &v->StutterEfficiencyNotIncludingVBlank, + &v->StutterEfficiency, + &v->NumberOfStutterBurstsPerFrame, + &v->Z8StutterEfficiencyNotIncludingVBlank, + &v->Z8StutterEfficiency, + &v->Z8NumberOfStutterBurstsPerFrame, + &v->StutterPeriod); +} + +static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib) +{ + struct vba_vars_st *v = &mode_lib->vba; + // Display Pipe Configuration + double BytePerPixDETY[DC__NUM_DPP__MAX]; + double BytePerPixDETC[DC__NUM_DPP__MAX]; + int BytePerPixY[DC__NUM_DPP__MAX]; + int BytePerPixC[DC__NUM_DPP__MAX]; + int Read256BytesBlockHeightY[DC__NUM_DPP__MAX]; + int Read256BytesBlockHeightC[DC__NUM_DPP__MAX]; + int Read256BytesBlockWidthY[DC__NUM_DPP__MAX]; + int Read256BytesBlockWidthC[DC__NUM_DPP__MAX]; + double dummy1[DC__NUM_DPP__MAX]; + double dummy2[DC__NUM_DPP__MAX]; + double dummy3[DC__NUM_DPP__MAX]; + double dummy4[DC__NUM_DPP__MAX]; + int dummy5[DC__NUM_DPP__MAX]; + int dummy6[DC__NUM_DPP__MAX]; + bool dummy7[DC__NUM_DPP__MAX]; + bool dummysinglestring; + + unsigned int k; + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + + CalculateBytePerPixelAnd256BBlockSizes( + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + &BytePerPixY[k], + &BytePerPixC[k], + &BytePerPixDETY[k], + &BytePerPixDETC[k], + &Read256BytesBlockHeightY[k], + &Read256BytesBlockHeightC[k], + &Read256BytesBlockWidthY[k], + &Read256BytesBlockWidthC[k]); + } + + CalculateSwathAndDETConfiguration( + false, + v->NumberOfActivePlanes, + v->DETBufferSizeInKByte[0], + dummy1, + dummy2, + v->SourceScan, + v->SourcePixelFormat, + v->SurfaceTiling, + v->ViewportWidth, + v->ViewportHeight, + v->SurfaceWidthY, + v->SurfaceWidthC, + v->SurfaceHeightY, + v->SurfaceHeightC, + Read256BytesBlockHeightY, + Read256BytesBlockHeightC, + Read256BytesBlockWidthY, + Read256BytesBlockWidthC, + v->ODMCombineEnabled, + v->BlendingAndTiming, + BytePerPixY, + BytePerPixC, + BytePerPixDETY, + BytePerPixDETC, + v->HActive, + v->HRatio, + v->HRatioChroma, + v->DPPPerPlane, + dummy5, + dummy6, + dummy3, + dummy4, + v->SwathHeightY, + v->SwathHeightC, + v->DETBufferSizeY, + v->DETBufferSizeC, + dummy7, + &dummysinglestring); +} + +static bool CalculateBytePerPixelAnd256BBlockSizes( + enum source_format_class SourcePixelFormat, + enum dm_swizzle_mode SurfaceTiling, + unsigned int *BytePerPixelY, + unsigned int *BytePerPixelC, + double *BytePerPixelDETY, + double *BytePerPixelDETC, + unsigned int *BlockHeight256BytesY, + unsigned int *BlockHeight256BytesC, + unsigned int *BlockWidth256BytesY, + unsigned int *BlockWidth256BytesC) +{ + if (SourcePixelFormat == dm_444_64) { + *BytePerPixelDETY = 8; + *BytePerPixelDETC = 0; + *BytePerPixelY = 8; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_32 || SourcePixelFormat == dm_rgbe) { + *BytePerPixelDETY = 4; + *BytePerPixelDETC = 0; + *BytePerPixelY = 4; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_16) { + *BytePerPixelDETY = 2; + *BytePerPixelDETC = 0; + *BytePerPixelY = 2; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_8) { + *BytePerPixelDETY = 1; + *BytePerPixelDETC = 0; + *BytePerPixelY = 1; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_rgbe_alpha) { + *BytePerPixelDETY = 4; + *BytePerPixelDETC = 1; + *BytePerPixelY = 4; + *BytePerPixelC = 1; + } else if (SourcePixelFormat == dm_420_8) { + *BytePerPixelDETY = 1; + *BytePerPixelDETC = 2; + *BytePerPixelY = 1; + *BytePerPixelC = 2; + } else if (SourcePixelFormat == dm_420_12) { + *BytePerPixelDETY = 2; + *BytePerPixelDETC = 4; + *BytePerPixelY = 2; + *BytePerPixelC = 4; + } else { + *BytePerPixelDETY = 4.0 / 3; + *BytePerPixelDETC = 8.0 / 3; + *BytePerPixelY = 2; + *BytePerPixelC = 4; + } + + if ((SourcePixelFormat == dm_444_64 || SourcePixelFormat == dm_444_32 || SourcePixelFormat == dm_444_16 || SourcePixelFormat == dm_444_8 || SourcePixelFormat == dm_mono_16 + || SourcePixelFormat == dm_mono_8 || SourcePixelFormat == dm_rgbe)) { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + } else if (SourcePixelFormat == dm_444_64) { + *BlockHeight256BytesY = 4; + } else if (SourcePixelFormat == dm_444_8) { + *BlockHeight256BytesY = 16; + } else { + *BlockHeight256BytesY = 8; + } + *BlockWidth256BytesY = 256U / *BytePerPixelY / *BlockHeight256BytesY; + *BlockHeight256BytesC = 0; + *BlockWidth256BytesC = 0; + } else { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + *BlockHeight256BytesC = 1; + } else if (SourcePixelFormat == dm_rgbe_alpha) { + *BlockHeight256BytesY = 8; + *BlockHeight256BytesC = 16; + } else if (SourcePixelFormat == dm_420_8) { + *BlockHeight256BytesY = 16; + *BlockHeight256BytesC = 8; + } else { + *BlockHeight256BytesY = 8; + *BlockHeight256BytesC = 8; + } + *BlockWidth256BytesY = 256U / *BytePerPixelY / *BlockHeight256BytesY; + *BlockWidth256BytesC = 256U / *BytePerPixelC / *BlockHeight256BytesC; + } + return true; +} + +static double CalculateTWait(unsigned int PrefetchMode, double DRAMClockChangeLatency, double UrgentLatency, double SREnterPlusExitTime) +{ + if (PrefetchMode == 0) { + return dml_max(DRAMClockChangeLatency + UrgentLatency, dml_max(SREnterPlusExitTime, UrgentLatency)); + } else if (PrefetchMode == 1) { + return dml_max(SREnterPlusExitTime, UrgentLatency); + } else { + return UrgentLatency; + } +} + +double dml31_CalculateWriteBackDISPCLK( + enum source_format_class WritebackPixelFormat, + double PixelClock, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackHTaps, + unsigned int WritebackVTaps, + long WritebackSourceWidth, + long WritebackDestinationWidth, + unsigned int HTotal, + unsigned int WritebackLineBufferSize) +{ + double DISPCLK_H, DISPCLK_V, DISPCLK_HB; + + DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; + DISPCLK_V = PixelClock * (WritebackVTaps * dml_ceil(WritebackDestinationWidth / 6.0, 1) + 8.0) / HTotal; + DISPCLK_HB = PixelClock * WritebackVTaps * (WritebackDestinationWidth * WritebackVTaps - WritebackLineBufferSize / 57.0) / 6.0 / WritebackSourceWidth; + return dml_max3(DISPCLK_H, DISPCLK_V, DISPCLK_HB); +} + +static double CalculateWriteBackDelay( + enum source_format_class WritebackPixelFormat, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackVTaps, + int WritebackDestinationWidth, + int WritebackDestinationHeight, + int WritebackSourceHeight, + unsigned int HTotal) +{ + double CalculateWriteBackDelay; + double Line_length; + double Output_lines_last_notclamped; + double WritebackVInit; + + WritebackVInit = (WritebackVRatio + WritebackVTaps + 1) / 2; + Line_length = dml_max((double) WritebackDestinationWidth, dml_ceil(WritebackDestinationWidth / 6.0, 1) * WritebackVTaps); + Output_lines_last_notclamped = WritebackDestinationHeight - 1 - dml_ceil((WritebackSourceHeight - WritebackVInit) / WritebackVRatio, 1); + if (Output_lines_last_notclamped < 0) { + CalculateWriteBackDelay = 0; + } else { + CalculateWriteBackDelay = Output_lines_last_notclamped * Line_length + (HTotal - WritebackDestinationWidth) + 80; + } + return CalculateWriteBackDelay; +} + +static void CalculateVupdateAndDynamicMetadataParameters( + int MaxInterDCNTileRepeaters, + double DPPCLK, + double DISPCLK, + double DCFClkDeepSleep, + double PixelClock, + int HTotal, + int VBlank, + int DynamicMetadataTransmittedBytes, + int DynamicMetadataLinesBeforeActiveRequired, + int InterlaceEnable, + bool ProgressiveToInterlaceUnitInOPP, + double *TSetup, + double *Tdmbf, + double *Tdmec, + double *Tdmsks, + int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix) +{ + double TotalRepeaterDelayTime; + + TotalRepeaterDelayTime = MaxInterDCNTileRepeaters * (2 / DPPCLK + 3 / DISPCLK); + *VUpdateWidthPix = dml_ceil((14.0 / DCFClkDeepSleep + 12.0 / DPPCLK + TotalRepeaterDelayTime) * PixelClock, 1.0); + *VReadyOffsetPix = dml_ceil(dml_max(150.0 / DPPCLK, TotalRepeaterDelayTime + 20.0 / DCFClkDeepSleep + 10.0 / DPPCLK) * PixelClock, 1.0); + *VUpdateOffsetPix = dml_ceil(HTotal / 4.0, 1); + *TSetup = (*VUpdateOffsetPix + *VUpdateWidthPix + *VReadyOffsetPix) / PixelClock; + *Tdmbf = DynamicMetadataTransmittedBytes / 4.0 / DISPCLK; + *Tdmec = HTotal / PixelClock; + if (DynamicMetadataLinesBeforeActiveRequired == 0) { + *Tdmsks = VBlank * HTotal / PixelClock / 2.0; + } else { + *Tdmsks = DynamicMetadataLinesBeforeActiveRequired * HTotal / PixelClock; + } + if (InterlaceEnable == 1 && ProgressiveToInterlaceUnitInOPP == false) { + *Tdmsks = *Tdmsks / 2; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VUpdateWidthPix = %d\n", __func__, *VUpdateWidthPix); + dml_print("DML::%s: VReadyOffsetPix = %d\n", __func__, *VReadyOffsetPix); + dml_print("DML::%s: VUpdateOffsetPix = %d\n", __func__, *VUpdateOffsetPix); +#endif +} + +static void CalculateRowBandwidth( + bool GPUVMEnable, + enum source_format_class SourcePixelFormat, + double VRatio, + double VRatioChroma, + bool DCCEnable, + double LineTime, + unsigned int MetaRowByteLuma, + unsigned int MetaRowByteChroma, + unsigned int meta_row_height_luma, + unsigned int meta_row_height_chroma, + unsigned int PixelPTEBytesPerRowLuma, + unsigned int PixelPTEBytesPerRowChroma, + unsigned int dpte_row_height_luma, + unsigned int dpte_row_height_chroma, + double *meta_row_bw, + double *dpte_row_bw) +{ + if (DCCEnable != true) { + *meta_row_bw = 0; + } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_420_12 || SourcePixelFormat == dm_rgbe_alpha) { + *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime) + VRatioChroma * MetaRowByteChroma / (meta_row_height_chroma * LineTime); + } else { + *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime); + } + + if (GPUVMEnable != true) { + *dpte_row_bw = 0; + } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_420_12 || SourcePixelFormat == dm_rgbe_alpha) { + *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime) + + VRatioChroma * PixelPTEBytesPerRowChroma / (dpte_row_height_chroma * LineTime); + } else { + *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime); + } +} + +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double HostVMInefficiencyFactor, + double UrgentExtraLatency, + double UrgentLatency, + unsigned int GPUVMMaxPageTableLevels, + bool HostVMEnable, + unsigned int HostVMMaxNonCachedPageTableLevels, + bool GPUVMEnable, + double HostVMMinPageSize, + double PDEAndMetaPTEBytesPerFrame, + double MetaRowBytes, + double DPTEBytesPerRow, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + double LineTime, + double VRatio, + double VRatioChroma, + double Tno_bw, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + unsigned int dpte_row_height_chroma, + unsigned int meta_row_height_chroma, + double *DestinationLinesToRequestVMInImmediateFlip, + double *DestinationLinesToRequestRowInImmediateFlip, + double *final_flip_bw, + bool *ImmediateFlipSupportedForPipe) +{ + double min_row_time = 0.0; + unsigned int HostVMDynamicLevelsTrips; + double TimeForFetchingMetaPTEImmediateFlip; + double TimeForFetchingRowInVBlankImmediateFlip; + double ImmediateFlipBW; + + if (GPUVMEnable == true && HostVMEnable == true) { + HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels; + } else { + HostVMDynamicLevelsTrips = 0; + } + + if (GPUVMEnable == true || DCCEnable == true) { + ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) * BandwidthAvailableForImmediateFlip / TotImmediateFlipBytes; + } + + if (GPUVMEnable == true) { + TimeForFetchingMetaPTEImmediateFlip = dml_max3( + Tno_bw + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW, + UrgentExtraLatency + UrgentLatency * (GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1), + LineTime / 4.0); + } else { + TimeForFetchingMetaPTEImmediateFlip = 0; + } + + *DestinationLinesToRequestVMInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0; + if ((GPUVMEnable == true || DCCEnable == true)) { + TimeForFetchingRowInVBlankImmediateFlip = dml_max3( + (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / ImmediateFlipBW, + UrgentLatency * (HostVMDynamicLevelsTrips + 1), + LineTime / 4); + } else { + TimeForFetchingRowInVBlankImmediateFlip = 0; + } + + *DestinationLinesToRequestRowInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0; + + if (GPUVMEnable == true) { + *final_flip_bw = dml_max( + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInImmediateFlip * LineTime), + (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime)); + } else if ((GPUVMEnable == true || DCCEnable == true)) { + *final_flip_bw = (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime); + } else { + *final_flip_bw = 0; + } + + if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_rgbe_alpha) { + if (GPUVMEnable == true && DCCEnable != true) { + min_row_time = dml_min(dpte_row_height * LineTime / VRatio, dpte_row_height_chroma * LineTime / VRatioChroma); + } else if (GPUVMEnable != true && DCCEnable == true) { + min_row_time = dml_min(meta_row_height * LineTime / VRatio, meta_row_height_chroma * LineTime / VRatioChroma); + } else { + min_row_time = dml_min4( + dpte_row_height * LineTime / VRatio, + meta_row_height * LineTime / VRatio, + dpte_row_height_chroma * LineTime / VRatioChroma, + meta_row_height_chroma * LineTime / VRatioChroma); + } + } else { + if (GPUVMEnable == true && DCCEnable != true) { + min_row_time = dpte_row_height * LineTime / VRatio; + } else if (GPUVMEnable != true && DCCEnable == true) { + min_row_time = meta_row_height * LineTime / VRatio; + } else { + min_row_time = dml_min(dpte_row_height * LineTime / VRatio, meta_row_height * LineTime / VRatio); + } + } + + if (*DestinationLinesToRequestVMInImmediateFlip >= 32 || *DestinationLinesToRequestRowInImmediateFlip >= 16 + || TimeForFetchingMetaPTEImmediateFlip + 2 * TimeForFetchingRowInVBlankImmediateFlip > min_row_time) { + *ImmediateFlipSupportedForPipe = false; + } else { + *ImmediateFlipSupportedForPipe = true; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: DestinationLinesToRequestVMInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestVMInImmediateFlip); + dml_print("DML::%s: DestinationLinesToRequestRowInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestRowInImmediateFlip); + dml_print("DML::%s: TimeForFetchingMetaPTEImmediateFlip = %f\n", __func__, TimeForFetchingMetaPTEImmediateFlip); + dml_print("DML::%s: TimeForFetchingRowInVBlankImmediateFlip = %f\n", __func__, TimeForFetchingRowInVBlankImmediateFlip); + dml_print("DML::%s: min_row_time = %f\n", __func__, min_row_time); + dml_print("DML::%s: ImmediateFlipSupportedForPipe = %d\n", __func__, *ImmediateFlipSupportedForPipe); +#endif + +} + +static double TruncToValidBPP( + double LinkBitRate, + int Lanes, + int HTotal, + int HActive, + double PixelClock, + double DesiredBPP, + bool DSCEnable, + enum output_encoder_class Output, + enum output_format_class Format, + unsigned int DSCInputBitPerComponent, + int DSCSlices, + int AudioRate, + int AudioLayout, + enum odm_combine_mode ODMCombine) +{ + double MaxLinkBPP; + int MinDSCBPP; + double MaxDSCBPP; + int NonDSCBPP0; + int NonDSCBPP1; + int NonDSCBPP2; + + if (Format == dm_420) { + NonDSCBPP0 = 12; + NonDSCBPP1 = 15; + NonDSCBPP2 = 18; + MinDSCBPP = 6; + MaxDSCBPP = 1.5 * DSCInputBitPerComponent - 1 / 16; + } else if (Format == dm_444) { + NonDSCBPP0 = 24; + NonDSCBPP1 = 30; + NonDSCBPP2 = 36; + MinDSCBPP = 8; + MaxDSCBPP = 3 * DSCInputBitPerComponent - 1.0 / 16; + } else { + if (Output == dm_hdmi) { + NonDSCBPP0 = 24; + NonDSCBPP1 = 24; + NonDSCBPP2 = 24; + } else { + NonDSCBPP0 = 16; + NonDSCBPP1 = 20; + NonDSCBPP2 = 24; + } + if (Format == dm_n422) { + MinDSCBPP = 7; + MaxDSCBPP = 2 * DSCInputBitPerComponent - 1.0 / 16.0; + } else { + MinDSCBPP = 8; + MaxDSCBPP = 3 * DSCInputBitPerComponent - 1.0 / 16.0; + } + } + + if (DSCEnable && Output == dm_dp) { + MaxLinkBPP = LinkBitRate / 10 * 8 * Lanes / PixelClock * (1 - 2.4 / 100); + } else { + MaxLinkBPP = LinkBitRate / 10 * 8 * Lanes / PixelClock; + } + + if (ODMCombine == dm_odm_combine_mode_4to1 && MaxLinkBPP > 16) { + MaxLinkBPP = 16; + } else if (ODMCombine == dm_odm_combine_mode_2to1 && MaxLinkBPP > 32) { + MaxLinkBPP = 32; + } + + if (DesiredBPP == 0) { + if (DSCEnable) { + if (MaxLinkBPP < MinDSCBPP) { + return BPP_INVALID; + } else if (MaxLinkBPP >= MaxDSCBPP) { + return MaxDSCBPP; + } else { + return dml_floor(16.0 * MaxLinkBPP, 1.0) / 16.0; + } + } else { + if (MaxLinkBPP >= NonDSCBPP2) { + return NonDSCBPP2; + } else if (MaxLinkBPP >= NonDSCBPP1) { + return NonDSCBPP1; + } else if (MaxLinkBPP >= NonDSCBPP0) { + return 16.0; + } else { + return BPP_INVALID; + } + } + } else { + if (!((DSCEnable == false && (DesiredBPP == NonDSCBPP2 || DesiredBPP == NonDSCBPP1 || DesiredBPP <= NonDSCBPP0)) + || (DSCEnable && DesiredBPP >= MinDSCBPP && DesiredBPP <= MaxDSCBPP))) { + return BPP_INVALID; + } else { + return DesiredBPP; + } + } + return BPP_INVALID; +} + +void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) +{ + struct vba_vars_st *v = &mode_lib->vba; + + int i, j; + unsigned int k, m; + int ReorderingBytes; + int MinPrefetchMode = 0, MaxPrefetchMode = 2; + bool NoChroma = true; + bool EnoughWritebackUnits = true; + bool P2IWith420 = false; + bool DSCOnlyIfNecessaryWithBPP = false; + bool DSC422NativeNotSupported = false; + double MaxTotalVActiveRDBandwidth; + bool ViewportExceedsSurface = false; + bool FMTBufferExceeded = false; + + /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/ + + CalculateMinAndMaxPrefetchMode( + mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, + &MinPrefetchMode, &MaxPrefetchMode); + + /*Scale Ratio, taps Support Check*/ + + v->ScaleRatioAndTapsSupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->ScalerEnabled[k] == false + && ((v->SourcePixelFormat[k] != dm_444_64 && v->SourcePixelFormat[k] != dm_444_32 + && v->SourcePixelFormat[k] != dm_444_16 && v->SourcePixelFormat[k] != dm_mono_16 + && v->SourcePixelFormat[k] != dm_mono_8 && v->SourcePixelFormat[k] != dm_rgbe + && v->SourcePixelFormat[k] != dm_rgbe_alpha) || v->HRatio[k] != 1.0 || v->htaps[k] != 1.0 + || v->VRatio[k] != 1.0 || v->vtaps[k] != 1.0)) { + v->ScaleRatioAndTapsSupport = false; + } else if (v->vtaps[k] < 1.0 || v->vtaps[k] > 8.0 || v->htaps[k] < 1.0 || v->htaps[k] > 8.0 + || (v->htaps[k] > 1.0 && (v->htaps[k] % 2) == 1) || v->HRatio[k] > v->MaxHSCLRatio + || v->VRatio[k] > v->MaxVSCLRatio || v->HRatio[k] > v->htaps[k] + || v->VRatio[k] > v->vtaps[k] + || (v->SourcePixelFormat[k] != dm_444_64 && v->SourcePixelFormat[k] != dm_444_32 + && v->SourcePixelFormat[k] != dm_444_16 && v->SourcePixelFormat[k] != dm_mono_16 + && v->SourcePixelFormat[k] != dm_mono_8 && v->SourcePixelFormat[k] != dm_rgbe + && (v->VTAPsChroma[k] < 1 || v->VTAPsChroma[k] > 8 || v->HTAPsChroma[k] < 1 + || v->HTAPsChroma[k] > 8 || (v->HTAPsChroma[k] > 1 && v->HTAPsChroma[k] % 2 == 1) + || v->HRatioChroma[k] > v->MaxHSCLRatio + || v->VRatioChroma[k] > v->MaxVSCLRatio + || v->HRatioChroma[k] > v->HTAPsChroma[k] + || v->VRatioChroma[k] > v->VTAPsChroma[k]))) { + v->ScaleRatioAndTapsSupport = false; + } + } + /*Source Format, Pixel Format and Scan Support Check*/ + + v->SourceFormatPixelAndScanSupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if ((v->SurfaceTiling[k] == dm_sw_linear && (!(v->SourceScan[k] != dm_vert) || v->DCCEnable[k] == true)) + || ((v->SurfaceTiling[k] == dm_sw_64kb_d || v->SurfaceTiling[k] == dm_sw_64kb_d_t + || v->SurfaceTiling[k] == dm_sw_64kb_d_x) && !(v->SourcePixelFormat[k] == dm_444_64))) { + v->SourceFormatPixelAndScanSupport = false; + } + } + /*Bandwidth Support Check*/ + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + CalculateBytePerPixelAnd256BBlockSizes( + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + &v->BytePerPixelY[k], + &v->BytePerPixelC[k], + &v->BytePerPixelInDETY[k], + &v->BytePerPixelInDETC[k], + &v->Read256BlockHeightY[k], + &v->Read256BlockHeightC[k], + &v->Read256BlockWidthY[k], + &v->Read256BlockWidthC[k]); + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->SourceScan[k] != dm_vert) { + v->SwathWidthYSingleDPP[k] = v->ViewportWidth[k]; + v->SwathWidthCSingleDPP[k] = v->ViewportWidthChroma[k]; + } else { + v->SwathWidthYSingleDPP[k] = v->ViewportHeight[k]; + v->SwathWidthCSingleDPP[k] = v->ViewportHeightChroma[k]; + } + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->ReadBandwidthLuma[k] = v->SwathWidthYSingleDPP[k] * dml_ceil(v->BytePerPixelInDETY[k], 1.0) + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k]; + v->ReadBandwidthChroma[k] = v->SwathWidthYSingleDPP[k] / 2 * dml_ceil(v->BytePerPixelInDETC[k], 2.0) + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k] / 2.0; + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->WritebackEnable[k] == true && v->WritebackPixelFormat[k] == dm_444_64) { + v->WriteBandwidth[k] = v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] + / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 8.0; + } else if (v->WritebackEnable[k] == true) { + v->WriteBandwidth[k] = v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] + / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4.0; + } else { + v->WriteBandwidth[k] = 0.0; + } + } + + /*Writeback Latency support check*/ + + v->WritebackLatencySupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->WritebackEnable[k] == true && (v->WriteBandwidth[k] > v->WritebackInterfaceBufferSize * 1024 / v->WritebackLatency)) { + v->WritebackLatencySupport = false; + } + } + + /*Writeback Mode Support Check*/ + + v->TotalNumberOfActiveWriteback = 0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->WritebackEnable[k] == true) { + v->TotalNumberOfActiveWriteback = v->TotalNumberOfActiveWriteback + 1; + } + } + + if (v->TotalNumberOfActiveWriteback > v->MaxNumWriteback) { + EnoughWritebackUnits = false; + } + + /*Writeback Scale Ratio and Taps Support Check*/ + + v->WritebackScaleRatioAndTapsSupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->WritebackEnable[k] == true) { + if (v->WritebackHRatio[k] > v->WritebackMaxHSCLRatio || v->WritebackVRatio[k] > v->WritebackMaxVSCLRatio + || v->WritebackHRatio[k] < v->WritebackMinHSCLRatio + || v->WritebackVRatio[k] < v->WritebackMinVSCLRatio + || v->WritebackHTaps[k] > v->WritebackMaxHSCLTaps + || v->WritebackVTaps[k] > v->WritebackMaxVSCLTaps + || v->WritebackHRatio[k] > v->WritebackHTaps[k] || v->WritebackVRatio[k] > v->WritebackVTaps[k] + || (v->WritebackHTaps[k] > 2.0 && ((v->WritebackHTaps[k] % 2) == 1))) { + v->WritebackScaleRatioAndTapsSupport = false; + } + if (2.0 * v->WritebackDestinationWidth[k] * (v->WritebackVTaps[k] - 1) * 57 > v->WritebackLineBufferSize) { + v->WritebackScaleRatioAndTapsSupport = false; + } + } + } + /*Maximum DISPCLK/DPPCLK Support check*/ + + v->WritebackRequiredDISPCLK = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->WritebackEnable[k] == true) { + v->WritebackRequiredDISPCLK = dml_max( + v->WritebackRequiredDISPCLK, + dml31_CalculateWriteBackDISPCLK( + v->WritebackPixelFormat[k], + v->PixelClock[k], + v->WritebackHRatio[k], + v->WritebackVRatio[k], + v->WritebackHTaps[k], + v->WritebackVTaps[k], + v->WritebackSourceWidth[k], + v->WritebackDestinationWidth[k], + v->HTotal[k], + v->WritebackLineBufferSize)); + } + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->HRatio[k] > 1.0) { + v->PSCL_FACTOR[k] = dml_min( + v->MaxDCHUBToPSCLThroughput, + v->MaxPSCLToLBThroughput * v->HRatio[k] / dml_ceil(v->htaps[k] / 6.0, 1.0)); + } else { + v->PSCL_FACTOR[k] = dml_min(v->MaxDCHUBToPSCLThroughput, v->MaxPSCLToLBThroughput); + } + if (v->BytePerPixelC[k] == 0.0) { + v->PSCL_FACTOR_CHROMA[k] = 0.0; + v->MinDPPCLKUsingSingleDPP[k] = v->PixelClock[k] + * dml_max3( + v->vtaps[k] / 6.0 * dml_min(1.0, v->HRatio[k]), + v->HRatio[k] * v->VRatio[k] / v->PSCL_FACTOR[k], + 1.0); + if ((v->htaps[k] > 6.0 || v->vtaps[k] > 6.0) && v->MinDPPCLKUsingSingleDPP[k] < 2.0 * v->PixelClock[k]) { + v->MinDPPCLKUsingSingleDPP[k] = 2.0 * v->PixelClock[k]; + } + } else { + if (v->HRatioChroma[k] > 1.0) { + v->PSCL_FACTOR_CHROMA[k] = dml_min( + v->MaxDCHUBToPSCLThroughput, + v->MaxPSCLToLBThroughput * v->HRatioChroma[k] / dml_ceil(v->HTAPsChroma[k] / 6.0, 1.0)); + } else { + v->PSCL_FACTOR_CHROMA[k] = dml_min(v->MaxDCHUBToPSCLThroughput, v->MaxPSCLToLBThroughput); + } + v->MinDPPCLKUsingSingleDPP[k] = v->PixelClock[k] + * dml_max5( + v->vtaps[k] / 6.0 * dml_min(1.0, v->HRatio[k]), + v->HRatio[k] * v->VRatio[k] / v->PSCL_FACTOR[k], + v->VTAPsChroma[k] / 6.0 * dml_min(1.0, v->HRatioChroma[k]), + v->HRatioChroma[k] * v->VRatioChroma[k] / v->PSCL_FACTOR_CHROMA[k], + 1.0); + if ((v->htaps[k] > 6.0 || v->vtaps[k] > 6.0 || v->HTAPsChroma[k] > 6.0 || v->VTAPsChroma[k] > 6.0) + && v->MinDPPCLKUsingSingleDPP[k] < 2.0 * v->PixelClock[k]) { + v->MinDPPCLKUsingSingleDPP[k] = 2.0 * v->PixelClock[k]; + } + } + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + int MaximumSwathWidthSupportLuma; + int MaximumSwathWidthSupportChroma; + + if (v->SurfaceTiling[k] == dm_sw_linear) { + MaximumSwathWidthSupportLuma = 8192.0; + } else if (v->SourceScan[k] == dm_vert && v->BytePerPixelC[k] > 0) { + MaximumSwathWidthSupportLuma = 2880.0; + } else if (v->SourcePixelFormat[k] == dm_rgbe_alpha) { + MaximumSwathWidthSupportLuma = 3840.0; + } else { + MaximumSwathWidthSupportLuma = 5760.0; + } + + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_420_12) { + MaximumSwathWidthSupportChroma = MaximumSwathWidthSupportLuma / 2.0; + } else { + MaximumSwathWidthSupportChroma = MaximumSwathWidthSupportLuma; + } + v->MaximumSwathWidthInLineBufferLuma = v->LineBufferSize * dml_max(v->HRatio[k], 1.0) / v->LBBitPerPixel[k] + / (v->vtaps[k] + dml_max(dml_ceil(v->VRatio[k], 1.0) - 2, 0.0)); + if (v->BytePerPixelC[k] == 0.0) { + v->MaximumSwathWidthInLineBufferChroma = 0; + } else { + v->MaximumSwathWidthInLineBufferChroma = v->LineBufferSize * dml_max(v->HRatioChroma[k], 1.0) / v->LBBitPerPixel[k] + / (v->VTAPsChroma[k] + dml_max(dml_ceil(v->VRatioChroma[k], 1.0) - 2, 0.0)); + } + v->MaximumSwathWidthLuma[k] = dml_min(MaximumSwathWidthSupportLuma, v->MaximumSwathWidthInLineBufferLuma); + v->MaximumSwathWidthChroma[k] = dml_min(MaximumSwathWidthSupportChroma, v->MaximumSwathWidthInLineBufferChroma); + } + + CalculateSwathAndDETConfiguration( + true, + v->NumberOfActivePlanes, + v->DETBufferSizeInKByte[0], + v->MaximumSwathWidthLuma, + v->MaximumSwathWidthChroma, + v->SourceScan, + v->SourcePixelFormat, + v->SurfaceTiling, + v->ViewportWidth, + v->ViewportHeight, + v->SurfaceWidthY, + v->SurfaceWidthC, + v->SurfaceHeightY, + v->SurfaceHeightC, + v->Read256BlockHeightY, + v->Read256BlockHeightC, + v->Read256BlockWidthY, + v->Read256BlockWidthC, + v->odm_combine_dummy, + v->BlendingAndTiming, + v->BytePerPixelY, + v->BytePerPixelC, + v->BytePerPixelInDETY, + v->BytePerPixelInDETC, + v->HActive, + v->HRatio, + v->HRatioChroma, + v->NoOfDPPThisState, + v->swath_width_luma_ub_this_state, + v->swath_width_chroma_ub_this_state, + v->SwathWidthYThisState, + v->SwathWidthCThisState, + v->SwathHeightYThisState, + v->SwathHeightCThisState, + v->DETBufferSizeYThisState, + v->DETBufferSizeCThisState, + v->SingleDPPViewportSizeSupportPerPlane, + &v->ViewportSizeSupport[0][0]); + + for (i = 0; i < v->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + v->MaxDispclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDispclk[i], v->DISPCLKDPPCLKVCOSpeed); + v->MaxDppclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDppclk[i], v->DISPCLKDPPCLKVCOSpeed); + v->RequiredDISPCLK[i][j] = 0.0; + v->DISPCLK_DPPCLK_Support[i][j] = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->PlaneRequiredDISPCLKWithoutODMCombine = v->PixelClock[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1.0 + v->DISPCLKRampingMargin / 100.0); + if ((v->PlaneRequiredDISPCLKWithoutODMCombine >= v->MaxDispclk[i] + && v->MaxDispclk[i] == v->MaxDispclk[v->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[v->soc.num_states - 1])) { + v->PlaneRequiredDISPCLKWithoutODMCombine = v->PixelClock[k] + * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + v->PlaneRequiredDISPCLKWithODMCombine2To1 = v->PixelClock[k] / 2 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1 + v->DISPCLKRampingMargin / 100.0); + if ((v->PlaneRequiredDISPCLKWithODMCombine2To1 >= v->MaxDispclk[i] + && v->MaxDispclk[i] == v->MaxDispclk[v->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[v->soc.num_states - 1])) { + v->PlaneRequiredDISPCLKWithODMCombine2To1 = v->PixelClock[k] / 2 + * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + v->PlaneRequiredDISPCLKWithODMCombine4To1 = v->PixelClock[k] / 4 * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1 + v->DISPCLKRampingMargin / 100.0); + if ((v->PlaneRequiredDISPCLKWithODMCombine4To1 >= v->MaxDispclk[i] + && v->MaxDispclk[i] == v->MaxDispclk[v->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[v->soc.num_states - 1])) { + v->PlaneRequiredDISPCLKWithODMCombine4To1 = v->PixelClock[k] / 4 + * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + + if (v->ODMCombinePolicy == dm_odm_combine_policy_none + || !(v->Output[k] == dm_dp || + v->Output[k] == dm_edp)) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithoutODMCombine; + + if (v->HActive[k] / 2 > DCN31_MAX_FMT_420_BUFFER_WIDTH) + FMTBufferExceeded = true; + } else if (v->ODMCombinePolicy == dm_odm_combine_policy_2to1) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; + } else if (v->ODMCombinePolicy == dm_odm_combine_policy_4to1 + || v->PlaneRequiredDISPCLKWithODMCombine2To1 > v->MaxDispclkRoundedDownToDFSGranularity) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_4to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine4To1; + } else if (v->PlaneRequiredDISPCLKWithoutODMCombine > v->MaxDispclkRoundedDownToDFSGranularity) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; + } else { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithoutODMCombine; + } + if (v->DSCEnabled[k] && v->HActive[k] > DCN31_MAX_DSC_IMAGE_WIDTH + && v->ODMCombineEnablePerState[i][k] != dm_odm_combine_mode_4to1) { + if (v->HActive[k] / 2 > DCN31_MAX_DSC_IMAGE_WIDTH) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_4to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine4To1; + } else { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; + } + } + if (v->OutputFormat[k] == dm_420 && v->HActive[k] > DCN31_MAX_FMT_420_BUFFER_WIDTH + && v->ODMCombineEnablePerState[i][k] != dm_odm_combine_mode_4to1) { + if (v->HActive[k] / 2 > DCN31_MAX_FMT_420_BUFFER_WIDTH) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_4to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine4To1; + + if (v->HActive[k] / 4 > DCN31_MAX_FMT_420_BUFFER_WIDTH) + FMTBufferExceeded = true; + } else { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1; + v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1; + } + } + if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1) { + v->MPCCombine[i][j][k] = false; + v->NoOfDPP[i][j][k] = 4; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 4; + } else if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_2to1) { + v->MPCCombine[i][j][k] = false; + v->NoOfDPP[i][j][k] = 2; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 2; + } else if ((v->WhenToDoMPCCombine == dm_mpc_never + || (v->MinDPPCLKUsingSingleDPP[k] * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + <= v->MaxDppclkRoundedDownToDFSGranularity && v->SingleDPPViewportSizeSupportPerPlane[k] == true))) { + v->MPCCombine[i][j][k] = false; + v->NoOfDPP[i][j][k] = 1; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } else { + v->MPCCombine[i][j][k] = true; + v->NoOfDPP[i][j][k] = 2; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 2.0; + } + v->RequiredDISPCLK[i][j] = dml_max(v->RequiredDISPCLK[i][j], v->PlaneRequiredDISPCLK); + if ((v->MinDPPCLKUsingSingleDPP[k] / v->NoOfDPP[i][j][k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + > v->MaxDppclkRoundedDownToDFSGranularity) + || (v->PlaneRequiredDISPCLK > v->MaxDispclkRoundedDownToDFSGranularity)) { + v->DISPCLK_DPPCLK_Support[i][j] = false; + } + } + v->TotalNumberOfActiveDPP[i][j] = 0; + v->TotalNumberOfSingleDPPPlanes[i][j] = 0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->TotalNumberOfActiveDPP[i][j] = v->TotalNumberOfActiveDPP[i][j] + v->NoOfDPP[i][j][k]; + if (v->NoOfDPP[i][j][k] == 1) + v->TotalNumberOfSingleDPPPlanes[i][j] = v->TotalNumberOfSingleDPPPlanes[i][j] + 1; + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 + || v->SourcePixelFormat[k] == dm_420_12 || v->SourcePixelFormat[k] == dm_rgbe_alpha) + NoChroma = false; + } + + // UPTO + if (j == 1 && v->WhenToDoMPCCombine != dm_mpc_never + && !UnboundedRequest(v->UseUnboundedRequesting, v->TotalNumberOfActiveDPP[i][j], NoChroma, v->Output[0])) { + while (!(v->TotalNumberOfActiveDPP[i][j] >= v->MaxNumDPP || v->TotalNumberOfSingleDPPPlanes[i][j] == 0)) { + double BWOfNonSplitPlaneOfMaximumBandwidth; + unsigned int NumberOfNonSplitPlaneOfMaximumBandwidth; + BWOfNonSplitPlaneOfMaximumBandwidth = 0; + NumberOfNonSplitPlaneOfMaximumBandwidth = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->ReadBandwidthLuma[k] + v->ReadBandwidthChroma[k] > BWOfNonSplitPlaneOfMaximumBandwidth + && v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_disabled && v->MPCCombine[i][j][k] == false) { + BWOfNonSplitPlaneOfMaximumBandwidth = v->ReadBandwidthLuma[k] + v->ReadBandwidthChroma[k]; + NumberOfNonSplitPlaneOfMaximumBandwidth = k; + } + } + v->MPCCombine[i][j][NumberOfNonSplitPlaneOfMaximumBandwidth] = true; + v->NoOfDPP[i][j][NumberOfNonSplitPlaneOfMaximumBandwidth] = 2; + v->RequiredDPPCLK[i][j][NumberOfNonSplitPlaneOfMaximumBandwidth] = + v->MinDPPCLKUsingSingleDPP[NumberOfNonSplitPlaneOfMaximumBandwidth] + * (1 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100) / 2; + v->TotalNumberOfActiveDPP[i][j] = v->TotalNumberOfActiveDPP[i][j] + 1; + v->TotalNumberOfSingleDPPPlanes[i][j] = v->TotalNumberOfSingleDPPPlanes[i][j] - 1; + } + } + if (v->TotalNumberOfActiveDPP[i][j] > v->MaxNumDPP) { + v->RequiredDISPCLK[i][j] = 0.0; + v->DISPCLK_DPPCLK_Support[i][j] = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled; + if (v->SingleDPPViewportSizeSupportPerPlane[k] == false && v->WhenToDoMPCCombine != dm_mpc_never) { + v->MPCCombine[i][j][k] = true; + v->NoOfDPP[i][j][k] = 2; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] + * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 2.0; + } else { + v->MPCCombine[i][j][k] = false; + v->NoOfDPP[i][j][k] = 1; + v->RequiredDPPCLK[i][j][k] = v->MinDPPCLKUsingSingleDPP[k] + * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + if (!(v->MaxDispclk[i] == v->MaxDispclk[v->soc.num_states - 1] + && v->MaxDppclk[i] == v->MaxDppclk[v->soc.num_states - 1])) { + v->PlaneRequiredDISPCLK = v->PixelClock[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1.0 + v->DISPCLKRampingMargin / 100.0); + } else { + v->PlaneRequiredDISPCLK = v->PixelClock[k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + v->RequiredDISPCLK[i][j] = dml_max(v->RequiredDISPCLK[i][j], v->PlaneRequiredDISPCLK); + if ((v->MinDPPCLKUsingSingleDPP[k] / v->NoOfDPP[i][j][k] * (1.0 + v->DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + > v->MaxDppclkRoundedDownToDFSGranularity) + || (v->PlaneRequiredDISPCLK > v->MaxDispclkRoundedDownToDFSGranularity)) { + v->DISPCLK_DPPCLK_Support[i][j] = false; + } + } + v->TotalNumberOfActiveDPP[i][j] = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->TotalNumberOfActiveDPP[i][j] = v->TotalNumberOfActiveDPP[i][j] + v->NoOfDPP[i][j][k]; + } + } + v->RequiredDISPCLK[i][j] = dml_max(v->RequiredDISPCLK[i][j], v->WritebackRequiredDISPCLK); + if (v->MaxDispclkRoundedDownToDFSGranularity < v->WritebackRequiredDISPCLK) { + v->DISPCLK_DPPCLK_Support[i][j] = false; + } + } + } + + /*Total Available Pipes Support Check*/ + + for (i = 0; i < v->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + if (v->TotalNumberOfActiveDPP[i][j] <= v->MaxNumDPP) { + v->TotalAvailablePipesSupport[i][j] = true; + } else { + v->TotalAvailablePipesSupport[i][j] = false; + } + } + } + /*Display IO and DSC Support Check*/ + + v->NonsupportedDSCInputBPC = false; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (!(v->DSCInputBitPerComponent[k] == 12.0 || v->DSCInputBitPerComponent[k] == 10.0 || v->DSCInputBitPerComponent[k] == 8.0) + || v->DSCInputBitPerComponent[k] > v->MaximumDSCBitsPerComponent) { + v->NonsupportedDSCInputBPC = true; + } + } + + /*Number Of DSC Slices*/ + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k) { + if (v->PixelClockBackEnd[k] > 3200) { + v->NumberOfDSCSlices[k] = dml_ceil(v->PixelClockBackEnd[k] / 400.0, 4.0); + } else if (v->PixelClockBackEnd[k] > 1360) { + v->NumberOfDSCSlices[k] = 8; + } else if (v->PixelClockBackEnd[k] > 680) { + v->NumberOfDSCSlices[k] = 4; + } else if (v->PixelClockBackEnd[k] > 340) { + v->NumberOfDSCSlices[k] = 2; + } else { + v->NumberOfDSCSlices[k] = 1; + } + } else { + v->NumberOfDSCSlices[k] = 0; + } + } + + for (i = 0; i < v->soc.num_states; i++) { + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->RequiresDSC[i][k] = false; + v->RequiresFEC[i][k] = false; + if (v->BlendingAndTiming[k] == k) { + if (v->Output[k] == dm_hdmi) { + v->RequiresDSC[i][k] = false; + v->RequiresFEC[i][k] = false; + v->OutputBppPerState[i][k] = TruncToValidBPP( + dml_min(600.0, v->PHYCLKPerState[i]) * 10, + 3, + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + false, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } else if (v->Output[k] == dm_dp || v->Output[k] == dm_edp) { + if (v->DSCEnable[k] == true) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + if (v->Output[k] == dm_dp) { + v->RequiresFEC[i][k] = true; + } else { + v->RequiresFEC[i][k] = false; + } + } else { + v->RequiresDSC[i][k] = false; + v->LinkDSCEnable = false; + v->RequiresFEC[i][k] = false; + } + + v->Outbpp = BPP_INVALID; + if (v->PHYCLKPerState[i] >= 270.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 2700, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 540.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 5400, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR2" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 810.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 8100, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR3" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 10000.0 / 18) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 10000, + 4, + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "10x4"; + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 12000.0 / 18) { + v->Outbpp = TruncToValidBPP( + 12000, + 4, + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "12x4"; + } + } + } else { + v->OutputBppPerState[i][k] = 0; + } + } + } + + for (i = 0; i < v->soc.num_states; i++) { + v->LinkCapacitySupport[i] = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->BlendingAndTiming[k] == k + && (v->Output[k] == dm_dp || + v->Output[k] == dm_edp || + v->Output[k] == dm_hdmi) && v->OutputBppPerState[i][k] == 0) { + v->LinkCapacitySupport[i] = false; + } + } + } + + // UPTO 2172 + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k + && (v->Output[k] == dm_dp || + v->Output[k] == dm_edp || + v->Output[k] == dm_hdmi)) { + if (v->OutputFormat[k] == dm_420 && v->Interlace[k] == 1 && v->ProgressiveToInterlaceUnitInOPP == true) { + P2IWith420 = true; + } + if (v->DSCEnable[k] == true && v->OutputFormat[k] == dm_n422 + && !v->DSC422NativeSupport) { + DSC422NativeNotSupported = true; + } + } + } + + for (i = 0; i < v->soc.num_states; ++i) { + v->ODMCombine4To1SupportCheckOK[i] = true; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k && v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1 + && (v->ODMCombine4To1Supported == false || v->Output[k] == dm_dp || v->Output[k] == dm_edp + || v->Output[k] == dm_hdmi)) { + v->ODMCombine4To1SupportCheckOK[i] = false; + } + } + } + + /* Skip dscclk validation: as long as dispclk is supported, dscclk is also implicitly supported */ + + for (i = 0; i < v->soc.num_states; i++) { + v->NotEnoughDSCUnits[i] = false; + v->TotalDSCUnitsRequired = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->RequiresDSC[i][k] == true) { + if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1) { + v->TotalDSCUnitsRequired = v->TotalDSCUnitsRequired + 4.0; + } else if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_2to1) { + v->TotalDSCUnitsRequired = v->TotalDSCUnitsRequired + 2.0; + } else { + v->TotalDSCUnitsRequired = v->TotalDSCUnitsRequired + 1.0; + } + } + } + if (v->TotalDSCUnitsRequired > v->NumberOfDSC) { + v->NotEnoughDSCUnits[i] = true; + } + } + /*DSC Delay per state*/ + + for (i = 0; i < v->soc.num_states; i++) { + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->OutputBppPerState[i][k] == BPP_INVALID) { + v->BPP = 0.0; + } else { + v->BPP = v->OutputBppPerState[i][k]; + } + if (v->RequiresDSC[i][k] == true && v->BPP != 0.0) { + if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_disabled) { + v->DSCDelayPerState[i][k] = dscceComputeDelay( + v->DSCInputBitPerComponent[k], + v->BPP, + dml_ceil(1.0 * v->HActive[k] / v->NumberOfDSCSlices[k], 1.0), + v->NumberOfDSCSlices[k], + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k]); + } else if (v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_2to1) { + v->DSCDelayPerState[i][k] = 2.0 + * (dscceComputeDelay( + v->DSCInputBitPerComponent[k], + v->BPP, + dml_ceil(1.0 * v->HActive[k] / v->NumberOfDSCSlices[k], 1.0), + v->NumberOfDSCSlices[k] / 2, + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k])); + } else { + v->DSCDelayPerState[i][k] = 4.0 + * (dscceComputeDelay( + v->DSCInputBitPerComponent[k], + v->BPP, + dml_ceil(1.0 * v->HActive[k] / v->NumberOfDSCSlices[k], 1.0), + v->NumberOfDSCSlices[k] / 4, + v->OutputFormat[k], + v->Output[k]) + dscComputeDelay(v->OutputFormat[k], v->Output[k])); + } + v->DSCDelayPerState[i][k] = v->DSCDelayPerState[i][k] * v->PixelClock[k] / v->PixelClockBackEnd[k]; + } else { + v->DSCDelayPerState[i][k] = 0.0; + } + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + for (m = 0; m < v->NumberOfActivePlanes; m++) { + if (v->BlendingAndTiming[k] == m && v->RequiresDSC[i][m] == true) { + v->DSCDelayPerState[i][k] = v->DSCDelayPerState[i][m]; + } + } + } + } + + //Calculate Swath, DET Configuration, DCFCLKDeepSleep + // + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->RequiredDPPCLKThisState[k] = v->RequiredDPPCLK[i][j][k]; + v->NoOfDPPThisState[k] = v->NoOfDPP[i][j][k]; + v->ODMCombineEnableThisState[k] = v->ODMCombineEnablePerState[i][k]; + } + + CalculateSwathAndDETConfiguration( + false, + v->NumberOfActivePlanes, + v->DETBufferSizeInKByte[0], + v->MaximumSwathWidthLuma, + v->MaximumSwathWidthChroma, + v->SourceScan, + v->SourcePixelFormat, + v->SurfaceTiling, + v->ViewportWidth, + v->ViewportHeight, + v->SurfaceWidthY, + v->SurfaceWidthC, + v->SurfaceHeightY, + v->SurfaceHeightC, + v->Read256BlockHeightY, + v->Read256BlockHeightC, + v->Read256BlockWidthY, + v->Read256BlockWidthC, + v->ODMCombineEnableThisState, + v->BlendingAndTiming, + v->BytePerPixelY, + v->BytePerPixelC, + v->BytePerPixelInDETY, + v->BytePerPixelInDETC, + v->HActive, + v->HRatio, + v->HRatioChroma, + v->NoOfDPPThisState, + v->swath_width_luma_ub_this_state, + v->swath_width_chroma_ub_this_state, + v->SwathWidthYThisState, + v->SwathWidthCThisState, + v->SwathHeightYThisState, + v->SwathHeightCThisState, + v->DETBufferSizeYThisState, + v->DETBufferSizeCThisState, + v->dummystring, + &v->ViewportSizeSupport[i][j]); + + CalculateDCFCLKDeepSleep( + mode_lib, + v->NumberOfActivePlanes, + v->BytePerPixelY, + v->BytePerPixelC, + v->VRatio, + v->VRatioChroma, + v->SwathWidthYThisState, + v->SwathWidthCThisState, + v->NoOfDPPThisState, + v->HRatio, + v->HRatioChroma, + v->PixelClock, + v->PSCL_FACTOR, + v->PSCL_FACTOR_CHROMA, + v->RequiredDPPCLKThisState, + v->ReadBandwidthLuma, + v->ReadBandwidthChroma, + v->ReturnBusWidth, + &v->ProjectedDCFCLKDeepSleep[i][j]); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->swath_width_luma_ub_all_states[i][j][k] = v->swath_width_luma_ub_this_state[k]; + v->swath_width_chroma_ub_all_states[i][j][k] = v->swath_width_chroma_ub_this_state[k]; + v->SwathWidthYAllStates[i][j][k] = v->SwathWidthYThisState[k]; + v->SwathWidthCAllStates[i][j][k] = v->SwathWidthCThisState[k]; + v->SwathHeightYAllStates[i][j][k] = v->SwathHeightYThisState[k]; + v->SwathHeightCAllStates[i][j][k] = v->SwathHeightCThisState[k]; + v->DETBufferSizeYAllStates[i][j][k] = v->DETBufferSizeYThisState[k]; + v->DETBufferSizeCAllStates[i][j][k] = v->DETBufferSizeCThisState[k]; + } + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->cursor_bw[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k]; + } + + for (i = 0; i < v->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + bool NotUrgentLatencyHiding[DC__NUM_DPP__MAX]; + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->swath_width_luma_ub_this_state[k] = v->swath_width_luma_ub_all_states[i][j][k]; + v->swath_width_chroma_ub_this_state[k] = v->swath_width_chroma_ub_all_states[i][j][k]; + v->SwathWidthYThisState[k] = v->SwathWidthYAllStates[i][j][k]; + v->SwathWidthCThisState[k] = v->SwathWidthCAllStates[i][j][k]; + v->SwathHeightYThisState[k] = v->SwathHeightYAllStates[i][j][k]; + v->SwathHeightCThisState[k] = v->SwathHeightCAllStates[i][j][k]; + v->DETBufferSizeYThisState[k] = v->DETBufferSizeYAllStates[i][j][k]; + v->DETBufferSizeCThisState[k] = v->DETBufferSizeCAllStates[i][j][k]; + } + + v->TotalNumberOfDCCActiveDPP[i][j] = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->DCCEnable[k] == true) { + v->TotalNumberOfDCCActiveDPP[i][j] = v->TotalNumberOfDCCActiveDPP[i][j] + v->NoOfDPP[i][j][k]; + } + } + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 + || v->SourcePixelFormat[k] == dm_420_12 || v->SourcePixelFormat[k] == dm_rgbe_alpha) { + + if ((v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_420_12) + && v->SourceScan[k] != dm_vert) { + v->PTEBufferSizeInRequestsForLuma = (v->PTEBufferSizeInRequestsLuma + v->PTEBufferSizeInRequestsChroma) + / 2; + v->PTEBufferSizeInRequestsForChroma = v->PTEBufferSizeInRequestsForLuma; + } else { + v->PTEBufferSizeInRequestsForLuma = v->PTEBufferSizeInRequestsLuma; + v->PTEBufferSizeInRequestsForChroma = v->PTEBufferSizeInRequestsChroma; + } + + v->PDEAndMetaPTEBytesPerFrameC = CalculateVMAndRowBytes( + mode_lib, + v->DCCEnable[k], + v->Read256BlockHeightC[k], + v->Read256BlockWidthC[k], + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + v->BytePerPixelC[k], + v->SourceScan[k], + v->SwathWidthCThisState[k], + v->ViewportHeightChroma[k], + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMMinPageSize, + v->HostVMMinPageSize, + v->PTEBufferSizeInRequestsForChroma, + v->PitchC[k], + 0.0, + &v->MacroTileWidthC[k], + &v->MetaRowBytesC, + &v->DPTEBytesPerRowC, + &v->PTEBufferSizeNotExceededC[i][j][k], + &v->dummyinteger7, + &v->dpte_row_height_chroma[k], + &v->dummyinteger28, + &v->dummyinteger26, + &v->dummyinteger23, + &v->meta_row_height_chroma[k], + &v->dummyinteger8, + &v->dummyinteger9, + &v->dummyinteger19, + &v->dummyinteger20, + &v->dummyinteger17, + &v->dummyinteger10, + &v->dummyinteger11); + + v->PrefetchLinesC[i][j][k] = CalculatePrefetchSourceLines( + mode_lib, + v->VRatioChroma[k], + v->VTAPsChroma[k], + v->Interlace[k], + v->ProgressiveToInterlaceUnitInOPP, + v->SwathHeightCThisState[k], + v->ViewportYStartC[k], + &v->PrefillC[k], + &v->MaxNumSwC[k]); + } else { + v->PTEBufferSizeInRequestsForLuma = v->PTEBufferSizeInRequestsLuma + v->PTEBufferSizeInRequestsChroma; + v->PTEBufferSizeInRequestsForChroma = 0; + v->PDEAndMetaPTEBytesPerFrameC = 0.0; + v->MetaRowBytesC = 0.0; + v->DPTEBytesPerRowC = 0.0; + v->PrefetchLinesC[i][j][k] = 0.0; + v->PTEBufferSizeNotExceededC[i][j][k] = true; + } + v->PDEAndMetaPTEBytesPerFrameY = CalculateVMAndRowBytes( + mode_lib, + v->DCCEnable[k], + v->Read256BlockHeightY[k], + v->Read256BlockWidthY[k], + v->SourcePixelFormat[k], + v->SurfaceTiling[k], + v->BytePerPixelY[k], + v->SourceScan[k], + v->SwathWidthYThisState[k], + v->ViewportHeight[k], + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMMinPageSize, + v->HostVMMinPageSize, + v->PTEBufferSizeInRequestsForLuma, + v->PitchY[k], + v->DCCMetaPitchY[k], + &v->MacroTileWidthY[k], + &v->MetaRowBytesY, + &v->DPTEBytesPerRowY, + &v->PTEBufferSizeNotExceededY[i][j][k], + &v->dummyinteger7, + &v->dpte_row_height[k], + &v->dummyinteger29, + &v->dummyinteger27, + &v->dummyinteger24, + &v->meta_row_height[k], + &v->dummyinteger25, + &v->dpte_group_bytes[k], + &v->dummyinteger21, + &v->dummyinteger22, + &v->dummyinteger18, + &v->dummyinteger5, + &v->dummyinteger6); + v->PrefetchLinesY[i][j][k] = CalculatePrefetchSourceLines( + mode_lib, + v->VRatio[k], + v->vtaps[k], + v->Interlace[k], + v->ProgressiveToInterlaceUnitInOPP, + v->SwathHeightYThisState[k], + v->ViewportYStartY[k], + &v->PrefillY[k], + &v->MaxNumSwY[k]); + v->PDEAndMetaPTEBytesPerFrame[i][j][k] = v->PDEAndMetaPTEBytesPerFrameY + v->PDEAndMetaPTEBytesPerFrameC; + v->MetaRowBytes[i][j][k] = v->MetaRowBytesY + v->MetaRowBytesC; + v->DPTEBytesPerRow[i][j][k] = v->DPTEBytesPerRowY + v->DPTEBytesPerRowC; + + CalculateRowBandwidth( + v->GPUVMEnable, + v->SourcePixelFormat[k], + v->VRatio[k], + v->VRatioChroma[k], + v->DCCEnable[k], + v->HTotal[k] / v->PixelClock[k], + v->MetaRowBytesY, + v->MetaRowBytesC, + v->meta_row_height[k], + v->meta_row_height_chroma[k], + v->DPTEBytesPerRowY, + v->DPTEBytesPerRowC, + v->dpte_row_height[k], + v->dpte_row_height_chroma[k], + &v->meta_row_bandwidth[i][j][k], + &v->dpte_row_bandwidth[i][j][k]); + } + v->UrgLatency[i] = CalculateUrgentLatency( + v->UrgentLatencyPixelDataOnly, + v->UrgentLatencyPixelMixedWithVMData, + v->UrgentLatencyVMDataOnly, + v->DoUrgentLatencyAdjustment, + v->UrgentLatencyAdjustmentFabricClockComponent, + v->UrgentLatencyAdjustmentFabricClockReference, + v->FabricClockPerState[i]); + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + CalculateUrgentBurstFactor( + v->swath_width_luma_ub_this_state[k], + v->swath_width_chroma_ub_this_state[k], + v->SwathHeightYThisState[k], + v->SwathHeightCThisState[k], + v->HTotal[k] / v->PixelClock[k], + v->UrgLatency[i], + v->CursorBufferSize, + v->CursorWidth[k][0], + v->CursorBPP[k][0], + v->VRatio[k], + v->VRatioChroma[k], + v->BytePerPixelInDETY[k], + v->BytePerPixelInDETC[k], + v->DETBufferSizeYThisState[k], + v->DETBufferSizeCThisState[k], + &v->UrgentBurstFactorCursor[k], + &v->UrgentBurstFactorLuma[k], + &v->UrgentBurstFactorChroma[k], + &NotUrgentLatencyHiding[k]); + } + + v->NotEnoughUrgentLatencyHidingA[i][j] = false; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (NotUrgentLatencyHiding[k]) { + v->NotEnoughUrgentLatencyHidingA[i][j] = true; + } + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->VActivePixelBandwidth[i][j][k] = v->ReadBandwidthLuma[k] * v->UrgentBurstFactorLuma[k] + + v->ReadBandwidthChroma[k] * v->UrgentBurstFactorChroma[k]; + v->VActiveCursorBandwidth[i][j][k] = v->cursor_bw[k] * v->UrgentBurstFactorCursor[k]; + } + + v->TotalVActivePixelBandwidth[i][j] = 0; + v->TotalVActiveCursorBandwidth[i][j] = 0; + v->TotalMetaRowBandwidth[i][j] = 0; + v->TotalDPTERowBandwidth[i][j] = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->TotalVActivePixelBandwidth[i][j] = v->TotalVActivePixelBandwidth[i][j] + v->VActivePixelBandwidth[i][j][k]; + v->TotalVActiveCursorBandwidth[i][j] = v->TotalVActiveCursorBandwidth[i][j] + v->VActiveCursorBandwidth[i][j][k]; + v->TotalMetaRowBandwidth[i][j] = v->TotalMetaRowBandwidth[i][j] + v->NoOfDPP[i][j][k] * v->meta_row_bandwidth[i][j][k]; + v->TotalDPTERowBandwidth[i][j] = v->TotalDPTERowBandwidth[i][j] + v->NoOfDPP[i][j][k] * v->dpte_row_bandwidth[i][j][k]; + } + } + } + + //Calculate Return BW + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->BlendingAndTiming[k] == k) { + if (v->WritebackEnable[k] == true) { + v->WritebackDelayTime[k] = v->WritebackLatency + + CalculateWriteBackDelay( + v->WritebackPixelFormat[k], + v->WritebackHRatio[k], + v->WritebackVRatio[k], + v->WritebackVTaps[k], + v->WritebackDestinationWidth[k], + v->WritebackDestinationHeight[k], + v->WritebackSourceHeight[k], + v->HTotal[k]) / v->RequiredDISPCLK[i][j]; + } else { + v->WritebackDelayTime[k] = 0.0; + } + for (m = 0; m < v->NumberOfActivePlanes; m++) { + if (v->BlendingAndTiming[m] == k && v->WritebackEnable[m] == true) { + v->WritebackDelayTime[k] = dml_max( + v->WritebackDelayTime[k], + v->WritebackLatency + + CalculateWriteBackDelay( + v->WritebackPixelFormat[m], + v->WritebackHRatio[m], + v->WritebackVRatio[m], + v->WritebackVTaps[m], + v->WritebackDestinationWidth[m], + v->WritebackDestinationHeight[m], + v->WritebackSourceHeight[m], + v->HTotal[m]) / v->RequiredDISPCLK[i][j]); + } + } + } + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + for (m = 0; m < v->NumberOfActivePlanes; m++) { + if (v->BlendingAndTiming[k] == m) { + v->WritebackDelayTime[k] = v->WritebackDelayTime[m]; + } + } + } + v->MaxMaxVStartup[i][j] = 0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->MaximumVStartup[i][j][k] = + (v->Interlace[k] && !v->ProgressiveToInterlaceUnitInOPP) ? + dml_floor((v->VTotal[k] - v->VActive[k]) / 2.0, 1.0) : + v->VTotal[k] - v->VActive[k] + - dml_max( + 1.0, + dml_ceil( + 1.0 * v->WritebackDelayTime[k] + / (v->HTotal[k] + / v->PixelClock[k]), + 1.0)); + if (v->MaximumVStartup[i][j][k] > 1023) + v->MaximumVStartup[i][j][k] = 1023; + v->MaxMaxVStartup[i][j] = dml_max(v->MaxMaxVStartup[i][j], v->MaximumVStartup[i][j][k]); + } + } + } + + ReorderingBytes = v->NumberOfChannels + * dml_max3( + v->UrgentOutOfOrderReturnPerChannelPixelDataOnly, + v->UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData, + v->UrgentOutOfOrderReturnPerChannelVMDataOnly); + + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + v->DCFCLKState[i][j] = v->DCFCLKPerState[i]; + } + } + + if (v->UseMinimumRequiredDCFCLK == true) { + UseMinimumDCFCLK( + mode_lib, + v->MaxInterDCNTileRepeaters, + MaxPrefetchMode, + v->DRAMClockChangeLatency, + v->SREnterPlusExitTime, + v->ReturnBusWidth, + v->RoundTripPingLatencyCycles, + ReorderingBytes, + v->PixelChunkSizeInKByte, + v->MetaChunkSize, + v->GPUVMEnable, + v->GPUVMMaxPageTableLevels, + v->HostVMEnable, + v->NumberOfActivePlanes, + v->HostVMMinPageSize, + v->HostVMMaxNonCachedPageTableLevels, + v->DynamicMetadataVMEnabled, + v->ImmediateFlipRequirement, + v->ProgressiveToInterlaceUnitInOPP, + v->MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation, + v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency, + v->VTotal, + v->VActive, + v->DynamicMetadataTransmittedBytes, + v->DynamicMetadataLinesBeforeActiveRequired, + v->Interlace, + v->RequiredDPPCLK, + v->RequiredDISPCLK, + v->UrgLatency, + v->NoOfDPP, + v->ProjectedDCFCLKDeepSleep, + v->MaximumVStartup, + v->TotalVActivePixelBandwidth, + v->TotalVActiveCursorBandwidth, + v->TotalMetaRowBandwidth, + v->TotalDPTERowBandwidth, + v->TotalNumberOfActiveDPP, + v->TotalNumberOfDCCActiveDPP, + v->dpte_group_bytes, + v->PrefetchLinesY, + v->PrefetchLinesC, + v->swath_width_luma_ub_all_states, + v->swath_width_chroma_ub_all_states, + v->BytePerPixelY, + v->BytePerPixelC, + v->HTotal, + v->PixelClock, + v->PDEAndMetaPTEBytesPerFrame, + v->DPTEBytesPerRow, + v->MetaRowBytes, + v->DynamicMetadataEnable, + v->VActivePixelBandwidth, + v->VActiveCursorBandwidth, + v->ReadBandwidthLuma, + v->ReadBandwidthChroma, + v->DCFCLKPerState, + v->DCFCLKState); + } + + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + double IdealFabricAndSDPPortBandwidthPerState = dml_min( + v->ReturnBusWidth * v->DCFCLKState[i][j], + v->FabricClockPerState[i] * v->FabricDatapathToDCNDataReturn); + double IdealDRAMBandwidthPerState = v->DRAMSpeedPerState[i] * v->NumberOfChannels * v->DRAMChannelWidth; + double PixelDataOnlyReturnBWPerState = dml_min( + IdealFabricAndSDPPortBandwidthPerState * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + IdealDRAMBandwidthPerState * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelDataOnly / 100.0); + double PixelMixedWithVMDataReturnBWPerState = dml_min( + IdealFabricAndSDPPortBandwidthPerState * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + IdealDRAMBandwidthPerState * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelMixedWithVMData / 100.0); + + if (v->HostVMEnable != true) { + v->ReturnBWPerState[i][j] = PixelDataOnlyReturnBWPerState; + } else { + v->ReturnBWPerState[i][j] = PixelMixedWithVMDataReturnBWPerState; + } + } + } + + //Re-ordering Buffer Support Check + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + if ((v->ROBBufferSizeInKByte - v->PixelChunkSizeInKByte) * 1024 / v->ReturnBWPerState[i][j] + > (v->RoundTripPingLatencyCycles + __DML_ARB_TO_RET_DELAY__) / v->DCFCLKState[i][j] + ReorderingBytes / v->ReturnBWPerState[i][j]) { + v->ROBSupport[i][j] = true; + } else { + v->ROBSupport[i][j] = false; + } + } + } + + //Vertical Active BW support check + + MaxTotalVActiveRDBandwidth = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + MaxTotalVActiveRDBandwidth = MaxTotalVActiveRDBandwidth + v->ReadBandwidthLuma[k] + v->ReadBandwidthChroma[k]; + } + + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + v->MaxTotalVerticalActiveAvailableBandwidth[i][j] = dml_min( + dml_min( + v->ReturnBusWidth * v->DCFCLKState[i][j], + v->FabricClockPerState[i] * v->FabricDatapathToDCNDataReturn) + * v->MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation / 100, + v->DRAMSpeedPerState[i] * v->NumberOfChannels * v->DRAMChannelWidth + * v->MaxAveragePercentOfIdealDRAMBWDisplayCanUseInNormalSystemOperation / 100); + + if (MaxTotalVActiveRDBandwidth <= v->MaxTotalVerticalActiveAvailableBandwidth[i][j]) { + v->TotalVerticalActiveBandwidthSupport[i][j] = true; + } else { + v->TotalVerticalActiveBandwidthSupport[i][j] = false; + } + } + } + + v->UrgentLatency = CalculateUrgentLatency( + v->UrgentLatencyPixelDataOnly, + v->UrgentLatencyPixelMixedWithVMData, + v->UrgentLatencyVMDataOnly, + v->DoUrgentLatencyAdjustment, + v->UrgentLatencyAdjustmentFabricClockComponent, + v->UrgentLatencyAdjustmentFabricClockReference, + v->FabricClock); + //Prefetch Check + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + double VMDataOnlyReturnBWPerState; + double HostVMInefficiencyFactor = 1; + int NextPrefetchModeState = MinPrefetchMode; + bool UnboundedRequestEnabledThisState = false; + int CompressedBufferSizeInkByteThisState = 0; + double dummy; + + v->TimeCalc = 24 / v->ProjectedDCFCLKDeepSleep[i][j]; + + v->BandwidthWithoutPrefetchSupported[i][j] = true; + if (v->TotalVActivePixelBandwidth[i][j] + v->TotalVActiveCursorBandwidth[i][j] + v->TotalMetaRowBandwidth[i][j] + + v->TotalDPTERowBandwidth[i][j] > v->ReturnBWPerState[i][j] || v->NotEnoughUrgentLatencyHidingA[i][j]) { + v->BandwidthWithoutPrefetchSupported[i][j] = false; + } + + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->NoOfDPPThisState[k] = v->NoOfDPP[i][j][k]; + v->swath_width_luma_ub_this_state[k] = v->swath_width_luma_ub_all_states[i][j][k]; + v->swath_width_chroma_ub_this_state[k] = v->swath_width_chroma_ub_all_states[i][j][k]; + v->SwathWidthYThisState[k] = v->SwathWidthYAllStates[i][j][k]; + v->SwathWidthCThisState[k] = v->SwathWidthCAllStates[i][j][k]; + v->SwathHeightYThisState[k] = v->SwathHeightYAllStates[i][j][k]; + v->SwathHeightCThisState[k] = v->SwathHeightCAllStates[i][j][k]; + v->DETBufferSizeYThisState[k] = v->DETBufferSizeYAllStates[i][j][k]; + v->DETBufferSizeCThisState[k] = v->DETBufferSizeCAllStates[i][j][k]; + } + + VMDataOnlyReturnBWPerState = dml_min( + dml_min( + v->ReturnBusWidth * v->DCFCLKState[i][j], + v->FabricClockPerState[i] * v->FabricDatapathToDCNDataReturn) + * v->PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0, + v->DRAMSpeedPerState[i] * v->NumberOfChannels * v->DRAMChannelWidth + * v->PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly / 100.0); + if (v->GPUVMEnable && v->HostVMEnable) + HostVMInefficiencyFactor = v->ReturnBWPerState[i][j] / VMDataOnlyReturnBWPerState; + + v->ExtraLatency = CalculateExtraLatency( + v->RoundTripPingLatencyCycles, + ReorderingBytes, + v->DCFCLKState[i][j], + v->TotalNumberOfActiveDPP[i][j], + v->PixelChunkSizeInKByte, + v->TotalNumberOfDCCActiveDPP[i][j], + v->MetaChunkSize, + v->ReturnBWPerState[i][j], + v->GPUVMEnable, + v->HostVMEnable, + v->NumberOfActivePlanes, + v->NoOfDPPThisState, + v->dpte_group_bytes, + HostVMInefficiencyFactor, + v->HostVMMinPageSize, + v->HostVMMaxNonCachedPageTableLevels); + + v->NextMaxVStartup = v->MaxMaxVStartup[i][j]; + do { + v->PrefetchModePerState[i][j] = NextPrefetchModeState; + v->MaxVStartup = v->NextMaxVStartup; + + v->TWait = CalculateTWait( + v->PrefetchModePerState[i][j], + v->DRAMClockChangeLatency, + v->UrgLatency[i], + v->SREnterPlusExitTime); + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + Pipe myPipe; + + myPipe.DPPCLK = v->RequiredDPPCLK[i][j][k]; + myPipe.DISPCLK = v->RequiredDISPCLK[i][j]; + myPipe.PixelClock = v->PixelClock[k]; + myPipe.DCFCLKDeepSleep = v->ProjectedDCFCLKDeepSleep[i][j]; + myPipe.DPPPerPlane = v->NoOfDPP[i][j][k]; + myPipe.ScalerEnabled = v->ScalerEnabled[k]; + myPipe.SourceScan = v->SourceScan[k]; + myPipe.BlockWidth256BytesY = v->Read256BlockWidthY[k]; + myPipe.BlockHeight256BytesY = v->Read256BlockHeightY[k]; + myPipe.BlockWidth256BytesC = v->Read256BlockWidthC[k]; + myPipe.BlockHeight256BytesC = v->Read256BlockHeightC[k]; + myPipe.InterlaceEnable = v->Interlace[k]; + myPipe.NumberOfCursors = v->NumberOfCursors[k]; + myPipe.VBlank = v->VTotal[k] - v->VActive[k]; + myPipe.HTotal = v->HTotal[k]; + myPipe.DCCEnable = v->DCCEnable[k]; + myPipe.ODMCombineIsEnabled = v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1 + || v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_2to1; + myPipe.SourcePixelFormat = v->SourcePixelFormat[k]; + myPipe.BytePerPixelY = v->BytePerPixelY[k]; + myPipe.BytePerPixelC = v->BytePerPixelC[k]; + myPipe.ProgressiveToInterlaceUnitInOPP = v->ProgressiveToInterlaceUnitInOPP; + v->NoTimeForPrefetch[i][j][k] = CalculatePrefetchSchedule( + mode_lib, + HostVMInefficiencyFactor, + &myPipe, + v->DSCDelayPerState[i][k], + v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater, + v->DPPCLKDelaySCL, + v->DPPCLKDelaySCLLBOnly, + v->DPPCLKDelayCNVCCursor, + v->DISPCLKDelaySubtotal, + v->SwathWidthYThisState[k] / v->HRatio[k], + v->OutputFormat[k], + v->MaxInterDCNTileRepeaters, + dml_min(v->MaxVStartup, v->MaximumVStartup[i][j][k]), + v->MaximumVStartup[i][j][k], + v->GPUVMMaxPageTableLevels, + v->GPUVMEnable, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->HostVMMinPageSize, + v->DynamicMetadataEnable[k], + v->DynamicMetadataVMEnabled, + v->DynamicMetadataLinesBeforeActiveRequired[k], + v->DynamicMetadataTransmittedBytes[k], + v->UrgLatency[i], + v->ExtraLatency, + v->TimeCalc, + v->PDEAndMetaPTEBytesPerFrame[i][j][k], + v->MetaRowBytes[i][j][k], + v->DPTEBytesPerRow[i][j][k], + v->PrefetchLinesY[i][j][k], + v->SwathWidthYThisState[k], + v->PrefillY[k], + v->MaxNumSwY[k], + v->PrefetchLinesC[i][j][k], + v->SwathWidthCThisState[k], + v->PrefillC[k], + v->MaxNumSwC[k], + v->swath_width_luma_ub_this_state[k], + v->swath_width_chroma_ub_this_state[k], + v->SwathHeightYThisState[k], + v->SwathHeightCThisState[k], + v->TWait, + &v->DSTXAfterScaler[k], + &v->DSTYAfterScaler[k], + &v->LineTimesForPrefetch[k], + &v->PrefetchBW[k], + &v->LinesForMetaPTE[k], + &v->LinesForMetaAndDPTERow[k], + &v->VRatioPreY[i][j][k], + &v->VRatioPreC[i][j][k], + &v->RequiredPrefetchPixelDataBWLuma[i][j][k], + &v->RequiredPrefetchPixelDataBWChroma[i][j][k], + &v->NoTimeForDynamicMetadata[i][j][k], + &v->Tno_bw[k], + &v->prefetch_vmrow_bw[k], + &v->dummy7[k], + &v->dummy8[k], + &v->dummy13[k], + &v->VUpdateOffsetPix[k], + &v->VUpdateWidthPix[k], + &v->VReadyOffsetPix[k]); + } + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + CalculateUrgentBurstFactor( + v->swath_width_luma_ub_this_state[k], + v->swath_width_chroma_ub_this_state[k], + v->SwathHeightYThisState[k], + v->SwathHeightCThisState[k], + v->HTotal[k] / v->PixelClock[k], + v->UrgentLatency, + v->CursorBufferSize, + v->CursorWidth[k][0], + v->CursorBPP[k][0], + v->VRatioPreY[i][j][k], + v->VRatioPreC[i][j][k], + v->BytePerPixelInDETY[k], + v->BytePerPixelInDETC[k], + v->DETBufferSizeYThisState[k], + v->DETBufferSizeCThisState[k], + &v->UrgentBurstFactorCursorPre[k], + &v->UrgentBurstFactorLumaPre[k], + &v->UrgentBurstFactorChroma[k], + &v->NotUrgentLatencyHidingPre[k]); + } + + v->MaximumReadBandwidthWithPrefetch = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->cursor_bw_pre[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 + / (v->HTotal[k] / v->PixelClock[k]) * v->VRatioPreY[i][j][k]; + + v->MaximumReadBandwidthWithPrefetch = + v->MaximumReadBandwidthWithPrefetch + + dml_max4( + v->VActivePixelBandwidth[i][j][k], + v->VActiveCursorBandwidth[i][j][k] + + v->NoOfDPP[i][j][k] + * (v->meta_row_bandwidth[i][j][k] + + v->dpte_row_bandwidth[i][j][k]), + v->NoOfDPP[i][j][k] * v->prefetch_vmrow_bw[k], + v->NoOfDPP[i][j][k] + * (v->RequiredPrefetchPixelDataBWLuma[i][j][k] + * v->UrgentBurstFactorLumaPre[k] + + v->RequiredPrefetchPixelDataBWChroma[i][j][k] + * v->UrgentBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgentBurstFactorCursorPre[k]); + } + + v->NotEnoughUrgentLatencyHidingPre = false; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->NotUrgentLatencyHidingPre[k] == true) { + v->NotEnoughUrgentLatencyHidingPre = true; + } + } + + v->PrefetchSupported[i][j] = true; + if (v->BandwidthWithoutPrefetchSupported[i][j] == false || v->MaximumReadBandwidthWithPrefetch > v->ReturnBWPerState[i][j] + || v->NotEnoughUrgentLatencyHidingPre == 1) { + v->PrefetchSupported[i][j] = false; + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->LineTimesForPrefetch[k] < 2.0 || v->LinesForMetaPTE[k] >= 32.0 || v->LinesForMetaAndDPTERow[k] >= 16.0 + || v->NoTimeForPrefetch[i][j][k] == true) { + v->PrefetchSupported[i][j] = false; + } + } + + v->DynamicMetadataSupported[i][j] = true; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->NoTimeForDynamicMetadata[i][j][k] == true) { + v->DynamicMetadataSupported[i][j] = false; + } + } + + v->VRatioInPrefetchSupported[i][j] = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->VRatioPreY[i][j][k] > 4.0 || v->VRatioPreC[i][j][k] > 4.0 || v->NoTimeForPrefetch[i][j][k] == true) { + v->VRatioInPrefetchSupported[i][j] = false; + } + } + v->AnyLinesForVMOrRowTooLarge = false; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->LinesForMetaAndDPTERow[k] >= 16 || v->LinesForMetaPTE[k] >= 32) { + v->AnyLinesForVMOrRowTooLarge = true; + } + } + + v->NextPrefetchMode = v->NextPrefetchMode + 1; + + if (v->PrefetchSupported[i][j] == true && v->VRatioInPrefetchSupported[i][j] == true) { + v->BandwidthAvailableForImmediateFlip = v->ReturnBWPerState[i][j]; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->BandwidthAvailableForImmediateFlip = v->BandwidthAvailableForImmediateFlip + - dml_max( + v->VActivePixelBandwidth[i][j][k] + v->VActiveCursorBandwidth[i][j][k], + v->NoOfDPP[i][j][k] + * (v->RequiredPrefetchPixelDataBWLuma[i][j][k] + * v->UrgentBurstFactorLumaPre[k] + + v->RequiredPrefetchPixelDataBWChroma[i][j][k] + * v->UrgentBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgentBurstFactorCursorPre[k]); + } + v->TotImmediateFlipBytes = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->TotImmediateFlipBytes = v->TotImmediateFlipBytes + + v->NoOfDPP[i][j][k] * v->PDEAndMetaPTEBytesPerFrame[i][j][k] + v->MetaRowBytes[i][j][k] + + v->DPTEBytesPerRow[i][j][k]; + } + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + CalculateFlipSchedule( + mode_lib, + HostVMInefficiencyFactor, + v->ExtraLatency, + v->UrgLatency[i], + v->GPUVMMaxPageTableLevels, + v->HostVMEnable, + v->HostVMMaxNonCachedPageTableLevels, + v->GPUVMEnable, + v->HostVMMinPageSize, + v->PDEAndMetaPTEBytesPerFrame[i][j][k], + v->MetaRowBytes[i][j][k], + v->DPTEBytesPerRow[i][j][k], + v->BandwidthAvailableForImmediateFlip, + v->TotImmediateFlipBytes, + v->SourcePixelFormat[k], + v->HTotal[k] / v->PixelClock[k], + v->VRatio[k], + v->VRatioChroma[k], + v->Tno_bw[k], + v->DCCEnable[k], + v->dpte_row_height[k], + v->meta_row_height[k], + v->dpte_row_height_chroma[k], + v->meta_row_height_chroma[k], + &v->DestinationLinesToRequestVMInImmediateFlip[k], + &v->DestinationLinesToRequestRowInImmediateFlip[k], + &v->final_flip_bw[k], + &v->ImmediateFlipSupportedForPipe[k]); + } + v->total_dcn_read_bw_with_flip = 0.0; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->total_dcn_read_bw_with_flip = v->total_dcn_read_bw_with_flip + + dml_max3( + v->NoOfDPP[i][j][k] * v->prefetch_vmrow_bw[k], + v->NoOfDPP[i][j][k] * v->final_flip_bw[k] + v->VActivePixelBandwidth[i][j][k] + + v->VActiveCursorBandwidth[i][j][k], + v->NoOfDPP[i][j][k] + * (v->final_flip_bw[k] + + v->RequiredPrefetchPixelDataBWLuma[i][j][k] + * v->UrgentBurstFactorLumaPre[k] + + v->RequiredPrefetchPixelDataBWChroma[i][j][k] + * v->UrgentBurstFactorChromaPre[k]) + + v->cursor_bw_pre[k] * v->UrgentBurstFactorCursorPre[k]); + } + v->ImmediateFlipSupportedForState[i][j] = true; + if (v->total_dcn_read_bw_with_flip > v->ReturnBWPerState[i][j]) { + v->ImmediateFlipSupportedForState[i][j] = false; + } + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->ImmediateFlipSupportedForPipe[k] == false) { + v->ImmediateFlipSupportedForState[i][j] = false; + } + } + } else { + v->ImmediateFlipSupportedForState[i][j] = false; + } + + if (v->MaxVStartup <= __DML_VBA_MIN_VSTARTUP__ || v->AnyLinesForVMOrRowTooLarge == false) { + v->NextMaxVStartup = v->MaxMaxVStartup[i][j]; + NextPrefetchModeState = NextPrefetchModeState + 1; + } else { + v->NextMaxVStartup = v->NextMaxVStartup - 1; + } + v->NextPrefetchMode = v->NextPrefetchMode + 1; + } while (!((v->PrefetchSupported[i][j] == true && v->DynamicMetadataSupported[i][j] == true && v->VRatioInPrefetchSupported[i][j] == true + && ((v->HostVMEnable == false && v->ImmediateFlipRequirement != dm_immediate_flip_required) + || v->ImmediateFlipSupportedForState[i][j] == true)) + || (v->NextMaxVStartup == v->MaxMaxVStartup[i][j] && NextPrefetchModeState > MaxPrefetchMode))); + + CalculateUnboundedRequestAndCompressedBufferSize( + v->DETBufferSizeInKByte[0], + v->ConfigReturnBufferSizeInKByte, + v->UseUnboundedRequesting, + v->TotalNumberOfActiveDPP[i][j], + NoChroma, + v->MaxNumDPP, + v->CompressedBufferSegmentSizeInkByte, + v->Output, + &UnboundedRequestEnabledThisState, + &CompressedBufferSizeInkByteThisState); + + CalculateWatermarksAndDRAMSpeedChangeSupport( + mode_lib, + v->PrefetchModePerState[i][j], + v->NumberOfActivePlanes, + v->MaxLineBufferLines, + v->LineBufferSize, + v->WritebackInterfaceBufferSize, + v->DCFCLKState[i][j], + v->ReturnBWPerState[i][j], + v->SynchronizedVBlank, + v->dpte_group_bytes, + v->MetaChunkSize, + v->UrgLatency[i], + v->ExtraLatency, + v->WritebackLatency, + v->WritebackChunkSize, + v->SOCCLKPerState[i], + v->DRAMClockChangeLatency, + v->SRExitTime, + v->SREnterPlusExitTime, + v->SRExitZ8Time, + v->SREnterPlusExitZ8Time, + v->ProjectedDCFCLKDeepSleep[i][j], + v->DETBufferSizeYThisState, + v->DETBufferSizeCThisState, + v->SwathHeightYThisState, + v->SwathHeightCThisState, + v->LBBitPerPixel, + v->SwathWidthYThisState, + v->SwathWidthCThisState, + v->HRatio, + v->HRatioChroma, + v->vtaps, + v->VTAPsChroma, + v->VRatio, + v->VRatioChroma, + v->HTotal, + v->PixelClock, + v->BlendingAndTiming, + v->NoOfDPPThisState, + v->BytePerPixelInDETY, + v->BytePerPixelInDETC, + v->DSTXAfterScaler, + v->DSTYAfterScaler, + v->WritebackEnable, + v->WritebackPixelFormat, + v->WritebackDestinationWidth, + v->WritebackDestinationHeight, + v->WritebackSourceHeight, + UnboundedRequestEnabledThisState, + CompressedBufferSizeInkByteThisState, + &v->DRAMClockChangeSupport[i][j], + &v->UrgentWatermark, + &v->WritebackUrgentWatermark, + &v->DRAMClockChangeWatermark, + &v->WritebackDRAMClockChangeWatermark, + &dummy, + &dummy, + &dummy, + &dummy, + &v->MinActiveDRAMClockChangeLatencySupported); + } + } + + /*PTE Buffer Size Check*/ + for (i = 0; i < v->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + v->PTEBufferSizeNotExceeded[i][j] = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->PTEBufferSizeNotExceededY[i][j][k] == false || v->PTEBufferSizeNotExceededC[i][j][k] == false) { + v->PTEBufferSizeNotExceeded[i][j] = false; + } + } + } + } + + /*Cursor Support Check*/ + v->CursorSupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->CursorWidth[k][0] > 0.0) { + if (v->CursorBPP[k][0] == 64 && v->Cursor64BppSupport == false) { + v->CursorSupport = false; + } + } + } + + /*Valid Pitch Check*/ + v->PitchSupport = true; + for (k = 0; k < v->NumberOfActivePlanes; k++) { + v->AlignedYPitch[k] = dml_ceil(dml_max(v->PitchY[k], v->SurfaceWidthY[k]), v->MacroTileWidthY[k]); + if (v->DCCEnable[k] == true) { + v->AlignedDCCMetaPitchY[k] = dml_ceil(dml_max(v->DCCMetaPitchY[k], v->SurfaceWidthY[k]), 64.0 * v->Read256BlockWidthY[k]); + } else { + v->AlignedDCCMetaPitchY[k] = v->DCCMetaPitchY[k]; + } + if (v->SourcePixelFormat[k] != dm_444_64 && v->SourcePixelFormat[k] != dm_444_32 && v->SourcePixelFormat[k] != dm_444_16 + && v->SourcePixelFormat[k] != dm_mono_16 && v->SourcePixelFormat[k] != dm_rgbe + && v->SourcePixelFormat[k] != dm_mono_8) { + v->AlignedCPitch[k] = dml_ceil(dml_max(v->PitchC[k], v->SurfaceWidthC[k]), v->MacroTileWidthC[k]); + if (v->DCCEnable[k] == true) { + v->AlignedDCCMetaPitchC[k] = dml_ceil( + dml_max(v->DCCMetaPitchC[k], v->SurfaceWidthC[k]), + 64.0 * v->Read256BlockWidthC[k]); + } else { + v->AlignedDCCMetaPitchC[k] = v->DCCMetaPitchC[k]; + } + } else { + v->AlignedCPitch[k] = v->PitchC[k]; + v->AlignedDCCMetaPitchC[k] = v->DCCMetaPitchC[k]; + } + if (v->AlignedYPitch[k] > v->PitchY[k] || v->AlignedCPitch[k] > v->PitchC[k] + || v->AlignedDCCMetaPitchY[k] > v->DCCMetaPitchY[k] || v->AlignedDCCMetaPitchC[k] > v->DCCMetaPitchC[k]) { + v->PitchSupport = false; + } + } + + for (k = 0; k < v->NumberOfActivePlanes; k++) { + if (v->ViewportWidth[k] > v->SurfaceWidthY[k] || v->ViewportHeight[k] > v->SurfaceHeightY[k]) { + ViewportExceedsSurface = true; + if (v->SourcePixelFormat[k] != dm_444_64 && v->SourcePixelFormat[k] != dm_444_32 + && v->SourcePixelFormat[k] != dm_444_16 && v->SourcePixelFormat[k] != dm_444_8 + && v->SourcePixelFormat[k] != dm_rgbe) { + if (v->ViewportWidthChroma[k] > v->SurfaceWidthC[k] + || v->ViewportHeightChroma[k] > v->SurfaceHeightC[k]) { + ViewportExceedsSurface = true; + } + } + } + } + + /*Mode Support, Voltage State and SOC Configuration*/ + for (i = v->soc.num_states - 1; i >= 0; i--) { + for (j = 0; j < 2; j++) { + if (v->ScaleRatioAndTapsSupport == true && v->SourceFormatPixelAndScanSupport == true && v->ViewportSizeSupport[i][j] == true + && v->LinkCapacitySupport[i] == true && !P2IWith420 && !DSCOnlyIfNecessaryWithBPP + && !DSC422NativeNotSupported && v->ODMCombine4To1SupportCheckOK[i] == true && v->NotEnoughDSCUnits[i] == false + && v->DTBCLKRequiredMoreThanSupported[i] == false + && v->ROBSupport[i][j] == true && v->DISPCLK_DPPCLK_Support[i][j] == true + && v->TotalAvailablePipesSupport[i][j] == true && EnoughWritebackUnits == true + && v->WritebackLatencySupport == true && v->WritebackScaleRatioAndTapsSupport == true + && v->CursorSupport == true && v->PitchSupport == true && ViewportExceedsSurface == false + && v->PrefetchSupported[i][j] == true && v->DynamicMetadataSupported[i][j] == true + && v->TotalVerticalActiveBandwidthSupport[i][j] == true && v->VRatioInPrefetchSupported[i][j] == true + && v->PTEBufferSizeNotExceeded[i][j] == true && v->NonsupportedDSCInputBPC == false + && ((v->HostVMEnable == false && v->ImmediateFlipRequirement != dm_immediate_flip_required) + || v->ImmediateFlipSupportedForState[i][j] == true) + && FMTBufferExceeded == false) { + v->ModeSupport[i][j] = true; + } else { + v->ModeSupport[i][j] = false; + } + } + } + + { + unsigned int MaximumMPCCombine = 0; + for (i = v->soc.num_states; i >= 0; i--) { + if (i == v->soc.num_states || v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true) { + v->VoltageLevel = i; + v->ModeIsSupported = v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true; + if (v->ModeSupport[i][0] == true) { + MaximumMPCCombine = 0; + } else { + MaximumMPCCombine = 1; + } + } + } + v->ImmediateFlipSupport = v->ImmediateFlipSupportedForState[v->VoltageLevel][MaximumMPCCombine]; + for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { + v->MPCCombineEnable[k] = v->MPCCombine[v->VoltageLevel][MaximumMPCCombine][k]; + v->DPPPerPlane[k] = v->NoOfDPP[v->VoltageLevel][MaximumMPCCombine][k]; + } + v->DCFCLK = v->DCFCLKState[v->VoltageLevel][MaximumMPCCombine]; + v->DRAMSpeed = v->DRAMSpeedPerState[v->VoltageLevel]; + v->FabricClock = v->FabricClockPerState[v->VoltageLevel]; + v->SOCCLK = v->SOCCLKPerState[v->VoltageLevel]; + v->ReturnBW = v->ReturnBWPerState[v->VoltageLevel][MaximumMPCCombine]; + v->maxMpcComb = MaximumMPCCombine; + } +} + +static void CalculateWatermarksAndDRAMSpeedChangeSupport( + struct display_mode_lib *mode_lib, + unsigned int PrefetchMode, + unsigned int NumberOfActivePlanes, + unsigned int MaxLineBufferLines, + unsigned int LineBufferSize, + unsigned int WritebackInterfaceBufferSize, + double DCFCLK, + double ReturnBW, + bool SynchronizedVBlank, + unsigned int dpte_group_bytes[], + unsigned int MetaChunkSize, + double UrgentLatency, + double ExtraLatency, + double WritebackLatency, + double WritebackChunkSize, + double SOCCLK, + double DRAMClockChangeLatency, + double SRExitTime, + double SREnterPlusExitTime, + double SRExitZ8Time, + double SREnterPlusExitZ8Time, + double DCFCLKDeepSleep, + unsigned int DETBufferSizeY[], + unsigned int DETBufferSizeC[], + unsigned int SwathHeightY[], + unsigned int SwathHeightC[], + unsigned int LBBitPerPixel[], + double SwathWidthY[], + double SwathWidthC[], + double HRatio[], + double HRatioChroma[], + unsigned int vtaps[], + unsigned int VTAPsChroma[], + double VRatio[], + double VRatioChroma[], + unsigned int HTotal[], + double PixelClock[], + unsigned int BlendingAndTiming[], + unsigned int DPPPerPlane[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + double DSTXAfterScaler[], + double DSTYAfterScaler[], + bool WritebackEnable[], + enum source_format_class WritebackPixelFormat[], + double WritebackDestinationWidth[], + double WritebackDestinationHeight[], + double WritebackSourceHeight[], + bool UnboundedRequestEnabled, + int unsigned CompressedBufferSizeInkByte, + enum clock_change_support *DRAMClockChangeSupport, + double *UrgentWatermark, + double *WritebackUrgentWatermark, + double *DRAMClockChangeWatermark, + double *WritebackDRAMClockChangeWatermark, + double *StutterExitWatermark, + double *StutterEnterPlusExitWatermark, + double *Z8StutterExitWatermark, + double *Z8StutterEnterPlusExitWatermark, + double *MinActiveDRAMClockChangeLatencySupported) +{ + struct vba_vars_st *v = &mode_lib->vba; + double EffectiveLBLatencyHidingY; + double EffectiveLBLatencyHidingC; + double LinesInDETY[DC__NUM_DPP__MAX]; + double LinesInDETC; + unsigned int LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX]; + unsigned int LinesInDETCRoundedDownToSwath; + double FullDETBufferingTimeY; + double FullDETBufferingTimeC; + double ActiveDRAMClockChangeLatencyMarginY; + double ActiveDRAMClockChangeLatencyMarginC; + double WritebackDRAMClockChangeLatencyMargin; + double PlaneWithMinActiveDRAMClockChangeMargin; + double SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank; + double WritebackDRAMClockChangeLatencyHiding; + double TotalPixelBW = 0.0; + int k, j; + + *UrgentWatermark = UrgentLatency + ExtraLatency; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: UrgentLatency = %f\n", __func__, UrgentLatency); + dml_print("DML::%s: ExtraLatency = %f\n", __func__, ExtraLatency); + dml_print("DML::%s: UrgentWatermark = %f\n", __func__, *UrgentWatermark); +#endif + + *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: DRAMClockChangeLatency = %f\n", __func__, DRAMClockChangeLatency); + dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, *DRAMClockChangeWatermark); +#endif + + v->TotalActiveWriteback = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (WritebackEnable[k] == true) { + v->TotalActiveWriteback = v->TotalActiveWriteback + 1; + } + } + + if (v->TotalActiveWriteback <= 1) { + *WritebackUrgentWatermark = WritebackLatency; + } else { + *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + } + + if (v->TotalActiveWriteback <= 1) { + *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency; + } else { + *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + TotalPixelBW = TotalPixelBW + + DPPPerPlane[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] + SwathWidthC[k] * BytePerPixelDETC[k] * VRatioChroma[k]) + / (HTotal[k] / PixelClock[k]); + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + double EffectiveDETBufferSizeY = DETBufferSizeY[k]; + + v->LBLatencyHidingSourceLinesY = dml_min( + (double) MaxLineBufferLines, + dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1); + + v->LBLatencyHidingSourceLinesC = dml_min( + (double) MaxLineBufferLines, + dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1); + + EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]); + + EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]); + + if (UnboundedRequestEnabled) { + EffectiveDETBufferSizeY = EffectiveDETBufferSizeY + + CompressedBufferSizeInkByte * 1024 * SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] / (HTotal[k] / PixelClock[k]) / TotalPixelBW; + } + + LinesInDETY[k] = (double) EffectiveDETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k]; + LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]); + FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k]; + if (BytePerPixelDETC[k] > 0) { + LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k]; + LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]); + FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k]; + } else { + LinesInDETC = 0; + FullDETBufferingTimeC = 999999; + } + + ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY + - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark; + + if (NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY + - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k]; + } + + if (BytePerPixelDETC[k] > 0) { + ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC + - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark; + + if (NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC + - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k]; + } + v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC); + } else { + v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY; + } + + if (WritebackEnable[k] == true) { + WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024 + / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4); + if (WritebackPixelFormat[k] == dm_444_64) { + WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2; + } + WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark; + v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(v->ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin); + } + } + + v->MinActiveDRAMClockChangeMargin = 999999; + PlaneWithMinActiveDRAMClockChangeMargin = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) { + v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k]; + if (BlendingAndTiming[k] == k) { + PlaneWithMinActiveDRAMClockChangeMargin = k; + } else { + for (j = 0; j < NumberOfActivePlanes; ++j) { + if (BlendingAndTiming[k] == j) { + PlaneWithMinActiveDRAMClockChangeMargin = j; + } + } + } + } + } + + *MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency; + + SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) + && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) { + SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k]; + } + } + + v->TotalNumberOfActiveOTG = 0; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (BlendingAndTiming[k] == k) { + v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1; + } + } + + if (v->MinActiveDRAMClockChangeMargin > 0 && PrefetchMode == 0) { + *DRAMClockChangeSupport = dm_dram_clock_change_vactive; + } else if ((SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 + || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0) { + *DRAMClockChangeSupport = dm_dram_clock_change_vblank; + } else { + *DRAMClockChangeSupport = dm_dram_clock_change_unsupported; + } + + *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep; + *StutterEnterPlusExitWatermark = (SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep); + *Z8StutterExitWatermark = SRExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; + *Z8StutterEnterPlusExitWatermark = SREnterPlusExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: StutterExitWatermark = %f\n", __func__, *StutterExitWatermark); + dml_print("DML::%s: StutterEnterPlusExitWatermark = %f\n", __func__, *StutterEnterPlusExitWatermark); + dml_print("DML::%s: Z8StutterExitWatermark = %f\n", __func__, *Z8StutterExitWatermark); + dml_print("DML::%s: Z8StutterEnterPlusExitWatermark = %f\n", __func__, *Z8StutterEnterPlusExitWatermark); +#endif +} + +static void CalculateDCFCLKDeepSleep( + struct display_mode_lib *mode_lib, + unsigned int NumberOfActivePlanes, + int BytePerPixelY[], + int BytePerPixelC[], + double VRatio[], + double VRatioChroma[], + double SwathWidthY[], + double SwathWidthC[], + unsigned int DPPPerPlane[], + double HRatio[], + double HRatioChroma[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double ReadBandwidthLuma[], + double ReadBandwidthChroma[], + int ReturnBusWidth, + double *DCFCLKDeepSleep) +{ + struct vba_vars_st *v = &mode_lib->vba; + double DisplayPipeLineDeliveryTimeLuma; + double DisplayPipeLineDeliveryTimeChroma; + double ReadBandwidth = 0.0; + int k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + + if (VRatio[k] <= 1) { + DisplayPipeLineDeliveryTimeLuma = SwathWidthY[k] * DPPPerPlane[k] / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLuma = SwathWidthY[k] / PSCL_THROUGHPUT[k] / DPPCLK[k]; + } + if (BytePerPixelC[k] == 0) { + DisplayPipeLineDeliveryTimeChroma = 0; + } else { + if (VRatioChroma[k] <= 1) { + DisplayPipeLineDeliveryTimeChroma = SwathWidthC[k] * DPPPerPlane[k] / HRatioChroma[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChroma = SwathWidthC[k] / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + + if (BytePerPixelC[k] > 0) { + v->DCFCLKDeepSleepPerPlane[k] = dml_max(__DML_MIN_DCFCLK_FACTOR__ * SwathWidthY[k] * BytePerPixelY[k] / 32.0 / DisplayPipeLineDeliveryTimeLuma, + __DML_MIN_DCFCLK_FACTOR__ * SwathWidthC[k] * BytePerPixelC[k] / 32.0 / DisplayPipeLineDeliveryTimeChroma); + } else { + v->DCFCLKDeepSleepPerPlane[k] = __DML_MIN_DCFCLK_FACTOR__ * SwathWidthY[k] * BytePerPixelY[k] / 64.0 / DisplayPipeLineDeliveryTimeLuma; + } + v->DCFCLKDeepSleepPerPlane[k] = dml_max(v->DCFCLKDeepSleepPerPlane[k], PixelClock[k] / 16); + + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + ReadBandwidth = ReadBandwidth + ReadBandwidthLuma[k] + ReadBandwidthChroma[k]; + } + + *DCFCLKDeepSleep = dml_max(8.0, __DML_MIN_DCFCLK_FACTOR__ * ReadBandwidth / ReturnBusWidth); + + for (k = 0; k < NumberOfActivePlanes; ++k) { + *DCFCLKDeepSleep = dml_max(*DCFCLKDeepSleep, v->DCFCLKDeepSleepPerPlane[k]); + } +} + +static void CalculateUrgentBurstFactor( + int swath_width_luma_ub, + int swath_width_chroma_ub, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double LineTime, + double UrgentLatency, + double CursorBufferSize, + unsigned int CursorWidth, + unsigned int CursorBPP, + double VRatio, + double VRatioC, + double BytePerPixelInDETY, + double BytePerPixelInDETC, + double DETBufferSizeY, + double DETBufferSizeC, + double *UrgentBurstFactorCursor, + double *UrgentBurstFactorLuma, + double *UrgentBurstFactorChroma, + bool *NotEnoughUrgentLatencyHiding) +{ + double LinesInDETLuma; + double LinesInDETChroma; + unsigned int LinesInCursorBuffer; + double CursorBufferSizeInTime; + double DETBufferSizeInTimeLuma; + double DETBufferSizeInTimeChroma; + + *NotEnoughUrgentLatencyHiding = 0; + + if (CursorWidth > 0) { + LinesInCursorBuffer = 1 << (unsigned int) dml_floor(dml_log2(CursorBufferSize * 1024.0 / (CursorWidth * CursorBPP / 8.0)), 1.0); + if (VRatio > 0) { + CursorBufferSizeInTime = LinesInCursorBuffer * LineTime / VRatio; + if (CursorBufferSizeInTime - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorCursor = 0; + } else { + *UrgentBurstFactorCursor = CursorBufferSizeInTime / (CursorBufferSizeInTime - UrgentLatency); + } + } else { + *UrgentBurstFactorCursor = 1; + } + } + + LinesInDETLuma = DETBufferSizeY / BytePerPixelInDETY / swath_width_luma_ub; + if (VRatio > 0) { + DETBufferSizeInTimeLuma = dml_floor(LinesInDETLuma, SwathHeightY) * LineTime / VRatio; + if (DETBufferSizeInTimeLuma - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorLuma = 0; + } else { + *UrgentBurstFactorLuma = DETBufferSizeInTimeLuma / (DETBufferSizeInTimeLuma - UrgentLatency); + } + } else { + *UrgentBurstFactorLuma = 1; + } + + if (BytePerPixelInDETC > 0) { + LinesInDETChroma = DETBufferSizeC / BytePerPixelInDETC / swath_width_chroma_ub; + if (VRatio > 0) { + DETBufferSizeInTimeChroma = dml_floor(LinesInDETChroma, SwathHeightC) * LineTime / VRatio; + if (DETBufferSizeInTimeChroma - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorChroma = 0; + } else { + *UrgentBurstFactorChroma = DETBufferSizeInTimeChroma / (DETBufferSizeInTimeChroma - UrgentLatency); + } + } else { + *UrgentBurstFactorChroma = 1; + } + } +} + +static void CalculatePixelDeliveryTimes( + unsigned int NumberOfActivePlanes, + double VRatio[], + double VRatioChroma[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + unsigned int swath_width_luma_ub[], + unsigned int swath_width_chroma_ub[], + unsigned int DPPPerPlane[], + double HRatio[], + double HRatioChroma[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + int BytePerPixelC[], + enum scan_direction_class SourceScan[], + unsigned int NumberOfCursors[], + unsigned int CursorWidth[][DC__NUM_CURSOR__MAX], + unsigned int CursorBPP[][DC__NUM_CURSOR__MAX], + unsigned int BlockWidth256BytesY[], + unsigned int BlockHeight256BytesY[], + unsigned int BlockWidth256BytesC[], + unsigned int BlockHeight256BytesC[], + double DisplayPipeLineDeliveryTimeLuma[], + double DisplayPipeLineDeliveryTimeChroma[], + double DisplayPipeLineDeliveryTimeLumaPrefetch[], + double DisplayPipeLineDeliveryTimeChromaPrefetch[], + double DisplayPipeRequestDeliveryTimeLuma[], + double DisplayPipeRequestDeliveryTimeChroma[], + double DisplayPipeRequestDeliveryTimeLumaPrefetch[], + double DisplayPipeRequestDeliveryTimeChromaPrefetch[], + double CursorRequestDeliveryTime[], + double CursorRequestDeliveryTimePrefetch[]) +{ + double req_per_swath_ub; + int k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (VRatio[k] <= 1) { + DisplayPipeLineDeliveryTimeLuma[k] = swath_width_luma_ub[k] * DPPPerPlane[k] / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLuma[k] = swath_width_luma_ub[k] / PSCL_THROUGHPUT[k] / DPPCLK[k]; + } + + if (BytePerPixelC[k] == 0) { + DisplayPipeLineDeliveryTimeChroma[k] = 0; + } else { + if (VRatioChroma[k] <= 1) { + DisplayPipeLineDeliveryTimeChroma[k] = swath_width_chroma_ub[k] * DPPPerPlane[k] / HRatioChroma[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChroma[k] = swath_width_chroma_ub[k] / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + + if (VRatioPrefetchY[k] <= 1) { + DisplayPipeLineDeliveryTimeLumaPrefetch[k] = swath_width_luma_ub[k] * DPPPerPlane[k] / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLumaPrefetch[k] = swath_width_luma_ub[k] / PSCL_THROUGHPUT[k] / DPPCLK[k]; + } + + if (BytePerPixelC[k] == 0) { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = 0; + } else { + if (VRatioPrefetchC[k] <= 1) { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = swath_width_chroma_ub[k] * DPPPerPlane[k] / HRatioChroma[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = swath_width_chroma_ub[k] / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (SourceScan[k] != dm_vert) { + req_per_swath_ub = swath_width_luma_ub[k] / BlockWidth256BytesY[k]; + } else { + req_per_swath_ub = swath_width_luma_ub[k] / BlockHeight256BytesY[k]; + } + DisplayPipeRequestDeliveryTimeLuma[k] = DisplayPipeLineDeliveryTimeLuma[k] / req_per_swath_ub; + DisplayPipeRequestDeliveryTimeLumaPrefetch[k] = DisplayPipeLineDeliveryTimeLumaPrefetch[k] / req_per_swath_ub; + if (BytePerPixelC[k] == 0) { + DisplayPipeRequestDeliveryTimeChroma[k] = 0; + DisplayPipeRequestDeliveryTimeChromaPrefetch[k] = 0; + } else { + if (SourceScan[k] != dm_vert) { + req_per_swath_ub = swath_width_chroma_ub[k] / BlockWidth256BytesC[k]; + } else { + req_per_swath_ub = swath_width_chroma_ub[k] / BlockHeight256BytesC[k]; + } + DisplayPipeRequestDeliveryTimeChroma[k] = DisplayPipeLineDeliveryTimeChroma[k] / req_per_swath_ub; + DisplayPipeRequestDeliveryTimeChromaPrefetch[k] = DisplayPipeLineDeliveryTimeChromaPrefetch[k] / req_per_swath_ub; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d : HRatio = %f\n", __func__, k, HRatio[k]); + dml_print("DML::%s: k=%d : VRatio = %f\n", __func__, k, VRatio[k]); + dml_print("DML::%s: k=%d : HRatioChroma = %f\n", __func__, k, HRatioChroma[k]); + dml_print("DML::%s: k=%d : VRatioChroma = %f\n", __func__, k, VRatioChroma[k]); + dml_print("DML::%s: k=%d : DisplayPipeLineDeliveryTimeLuma = %f\n", __func__, k, DisplayPipeLineDeliveryTimeLuma[k]); + dml_print("DML::%s: k=%d : DisplayPipeLineDeliveryTimeLumaPrefetch = %f\n", __func__, k, DisplayPipeLineDeliveryTimeLumaPrefetch[k]); + dml_print("DML::%s: k=%d : DisplayPipeLineDeliveryTimeChroma = %f\n", __func__, k, DisplayPipeLineDeliveryTimeChroma[k]); + dml_print("DML::%s: k=%d : DisplayPipeLineDeliveryTimeChromaPrefetch = %f\n", __func__, k, DisplayPipeLineDeliveryTimeChromaPrefetch[k]); + dml_print("DML::%s: k=%d : DisplayPipeRequestDeliveryTimeLuma = %f\n", __func__, k, DisplayPipeRequestDeliveryTimeLuma[k]); + dml_print("DML::%s: k=%d : DisplayPipeRequestDeliveryTimeLumaPrefetch = %f\n", __func__, k, DisplayPipeRequestDeliveryTimeLumaPrefetch[k]); + dml_print("DML::%s: k=%d : DisplayPipeRequestDeliveryTimeChroma = %f\n", __func__, k, DisplayPipeRequestDeliveryTimeChroma[k]); + dml_print("DML::%s: k=%d : DisplayPipeRequestDeliveryTimeChromaPrefetch = %f\n", __func__, k, DisplayPipeRequestDeliveryTimeChromaPrefetch[k]); +#endif + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + int cursor_req_per_width; + cursor_req_per_width = dml_ceil(CursorWidth[k][0] * CursorBPP[k][0] / 256 / 8, 1); + if (NumberOfCursors[k] > 0) { + if (VRatio[k] <= 1) { + CursorRequestDeliveryTime[k] = CursorWidth[k][0] / HRatio[k] / PixelClock[k] / cursor_req_per_width; + } else { + CursorRequestDeliveryTime[k] = CursorWidth[k][0] / PSCL_THROUGHPUT[k] / DPPCLK[k] / cursor_req_per_width; + } + if (VRatioPrefetchY[k] <= 1) { + CursorRequestDeliveryTimePrefetch[k] = CursorWidth[k][0] / HRatio[k] / PixelClock[k] / cursor_req_per_width; + } else { + CursorRequestDeliveryTimePrefetch[k] = CursorWidth[k][0] / PSCL_THROUGHPUT[k] / DPPCLK[k] / cursor_req_per_width; + } + } else { + CursorRequestDeliveryTime[k] = 0; + CursorRequestDeliveryTimePrefetch[k] = 0; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d : NumberOfCursors = %d\n", __func__, k, NumberOfCursors[k]); + dml_print("DML::%s: k=%d : CursorRequestDeliveryTime = %f\n", __func__, k, CursorRequestDeliveryTime[k]); + dml_print("DML::%s: k=%d : CursorRequestDeliveryTimePrefetch = %f\n", __func__, k, CursorRequestDeliveryTimePrefetch[k]); +#endif + } +} + +static void CalculateMetaAndPTETimes( + int NumberOfActivePlanes, + bool GPUVMEnable, + int MetaChunkSize, + int MinMetaChunkSizeBytes, + int HTotal[], + double VRatio[], + double VRatioChroma[], + double DestinationLinesToRequestRowInVBlank[], + double DestinationLinesToRequestRowInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + int BytePerPixelY[], + int BytePerPixelC[], + enum scan_direction_class SourceScan[], + int dpte_row_height[], + int dpte_row_height_chroma[], + int meta_row_width[], + int meta_row_width_chroma[], + int meta_row_height[], + int meta_row_height_chroma[], + int meta_req_width[], + int meta_req_width_chroma[], + int meta_req_height[], + int meta_req_height_chroma[], + int dpte_group_bytes[], + int PTERequestSizeY[], + int PTERequestSizeC[], + int PixelPTEReqWidthY[], + int PixelPTEReqHeightY[], + int PixelPTEReqWidthC[], + int PixelPTEReqHeightC[], + int dpte_row_width_luma_ub[], + int dpte_row_width_chroma_ub[], + double DST_Y_PER_PTE_ROW_NOM_L[], + double DST_Y_PER_PTE_ROW_NOM_C[], + double DST_Y_PER_META_ROW_NOM_L[], + double DST_Y_PER_META_ROW_NOM_C[], + double TimePerMetaChunkNominal[], + double TimePerChromaMetaChunkNominal[], + double TimePerMetaChunkVBlank[], + double TimePerChromaMetaChunkVBlank[], + double TimePerMetaChunkFlip[], + double TimePerChromaMetaChunkFlip[], + double time_per_pte_group_nom_luma[], + double time_per_pte_group_vblank_luma[], + double time_per_pte_group_flip_luma[], + double time_per_pte_group_nom_chroma[], + double time_per_pte_group_vblank_chroma[], + double time_per_pte_group_flip_chroma[]) +{ + unsigned int meta_chunk_width; + unsigned int min_meta_chunk_width; + unsigned int meta_chunk_per_row_int; + unsigned int meta_row_remainder; + unsigned int meta_chunk_threshold; + unsigned int meta_chunks_per_row_ub; + unsigned int meta_chunk_width_chroma; + unsigned int min_meta_chunk_width_chroma; + unsigned int meta_chunk_per_row_int_chroma; + unsigned int meta_row_remainder_chroma; + unsigned int meta_chunk_threshold_chroma; + unsigned int meta_chunks_per_row_ub_chroma; + unsigned int dpte_group_width_luma; + unsigned int dpte_groups_per_row_luma_ub; + unsigned int dpte_group_width_chroma; + unsigned int dpte_groups_per_row_chroma_ub; + int k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + DST_Y_PER_PTE_ROW_NOM_L[k] = dpte_row_height[k] / VRatio[k]; + if (BytePerPixelC[k] == 0) { + DST_Y_PER_PTE_ROW_NOM_C[k] = 0; + } else { + DST_Y_PER_PTE_ROW_NOM_C[k] = dpte_row_height_chroma[k] / VRatioChroma[k]; + } + DST_Y_PER_META_ROW_NOM_L[k] = meta_row_height[k] / VRatio[k]; + if (BytePerPixelC[k] == 0) { + DST_Y_PER_META_ROW_NOM_C[k] = 0; + } else { + DST_Y_PER_META_ROW_NOM_C[k] = meta_row_height_chroma[k] / VRatioChroma[k]; + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (DCCEnable[k] == true) { + meta_chunk_width = MetaChunkSize * 1024 * 256 / BytePerPixelY[k] / meta_row_height[k]; + min_meta_chunk_width = MinMetaChunkSizeBytes * 256 / BytePerPixelY[k] / meta_row_height[k]; + meta_chunk_per_row_int = meta_row_width[k] / meta_chunk_width; + meta_row_remainder = meta_row_width[k] % meta_chunk_width; + if (SourceScan[k] != dm_vert) { + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_width[k]; + } else { + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_height[k]; + } + if (meta_row_remainder <= meta_chunk_threshold) { + meta_chunks_per_row_ub = meta_chunk_per_row_int + 1; + } else { + meta_chunks_per_row_ub = meta_chunk_per_row_int + 2; + } + TimePerMetaChunkNominal[k] = meta_row_height[k] / VRatio[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub; + TimePerMetaChunkVBlank[k] = DestinationLinesToRequestRowInVBlank[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub; + TimePerMetaChunkFlip[k] = DestinationLinesToRequestRowInImmediateFlip[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub; + if (BytePerPixelC[k] == 0) { + TimePerChromaMetaChunkNominal[k] = 0; + TimePerChromaMetaChunkVBlank[k] = 0; + TimePerChromaMetaChunkFlip[k] = 0; + } else { + meta_chunk_width_chroma = MetaChunkSize * 1024 * 256 / BytePerPixelC[k] / meta_row_height_chroma[k]; + min_meta_chunk_width_chroma = MinMetaChunkSizeBytes * 256 / BytePerPixelC[k] / meta_row_height_chroma[k]; + meta_chunk_per_row_int_chroma = (double) meta_row_width_chroma[k] / meta_chunk_width_chroma; + meta_row_remainder_chroma = meta_row_width_chroma[k] % meta_chunk_width_chroma; + if (SourceScan[k] != dm_vert) { + meta_chunk_threshold_chroma = 2 * min_meta_chunk_width_chroma - meta_req_width_chroma[k]; + } else { + meta_chunk_threshold_chroma = 2 * min_meta_chunk_width_chroma - meta_req_height_chroma[k]; + } + if (meta_row_remainder_chroma <= meta_chunk_threshold_chroma) { + meta_chunks_per_row_ub_chroma = meta_chunk_per_row_int_chroma + 1; + } else { + meta_chunks_per_row_ub_chroma = meta_chunk_per_row_int_chroma + 2; + } + TimePerChromaMetaChunkNominal[k] = meta_row_height_chroma[k] / VRatioChroma[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub_chroma; + TimePerChromaMetaChunkVBlank[k] = DestinationLinesToRequestRowInVBlank[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub_chroma; + TimePerChromaMetaChunkFlip[k] = DestinationLinesToRequestRowInImmediateFlip[k] * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub_chroma; + } + } else { + TimePerMetaChunkNominal[k] = 0; + TimePerMetaChunkVBlank[k] = 0; + TimePerMetaChunkFlip[k] = 0; + TimePerChromaMetaChunkNominal[k] = 0; + TimePerChromaMetaChunkVBlank[k] = 0; + TimePerChromaMetaChunkFlip[k] = 0; + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (GPUVMEnable == true) { + if (SourceScan[k] != dm_vert) { + dpte_group_width_luma = dpte_group_bytes[k] / PTERequestSizeY[k] * PixelPTEReqWidthY[k]; + } else { + dpte_group_width_luma = dpte_group_bytes[k] / PTERequestSizeY[k] * PixelPTEReqHeightY[k]; + } + dpte_groups_per_row_luma_ub = dml_ceil(1.0 * dpte_row_width_luma_ub[k] / dpte_group_width_luma, 1); + time_per_pte_group_nom_luma[k] = DST_Y_PER_PTE_ROW_NOM_L[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_luma_ub; + time_per_pte_group_vblank_luma[k] = DestinationLinesToRequestRowInVBlank[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_luma_ub; + time_per_pte_group_flip_luma[k] = DestinationLinesToRequestRowInImmediateFlip[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_luma_ub; + if (BytePerPixelC[k] == 0) { + time_per_pte_group_nom_chroma[k] = 0; + time_per_pte_group_vblank_chroma[k] = 0; + time_per_pte_group_flip_chroma[k] = 0; + } else { + if (SourceScan[k] != dm_vert) { + dpte_group_width_chroma = dpte_group_bytes[k] / PTERequestSizeC[k] * PixelPTEReqWidthC[k]; + } else { + dpte_group_width_chroma = dpte_group_bytes[k] / PTERequestSizeC[k] * PixelPTEReqHeightC[k]; + } + dpte_groups_per_row_chroma_ub = dml_ceil(1.0 * dpte_row_width_chroma_ub[k] / dpte_group_width_chroma, 1); + time_per_pte_group_nom_chroma[k] = DST_Y_PER_PTE_ROW_NOM_C[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_chroma_ub; + time_per_pte_group_vblank_chroma[k] = DestinationLinesToRequestRowInVBlank[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_chroma_ub; + time_per_pte_group_flip_chroma[k] = DestinationLinesToRequestRowInImmediateFlip[k] * HTotal[k] / PixelClock[k] / dpte_groups_per_row_chroma_ub; + } + } else { + time_per_pte_group_nom_luma[k] = 0; + time_per_pte_group_vblank_luma[k] = 0; + time_per_pte_group_flip_luma[k] = 0; + time_per_pte_group_nom_chroma[k] = 0; + time_per_pte_group_vblank_chroma[k] = 0; + time_per_pte_group_flip_chroma[k] = 0; + } + } +} + +static void CalculateVMGroupAndRequestTimes( + unsigned int NumberOfActivePlanes, + bool GPUVMEnable, + unsigned int GPUVMMaxPageTableLevels, + unsigned int HTotal[], + int BytePerPixelC[], + double DestinationLinesToRequestVMInVBlank[], + double DestinationLinesToRequestVMInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + int dpte_row_width_luma_ub[], + int dpte_row_width_chroma_ub[], + int vm_group_bytes[], + unsigned int dpde0_bytes_per_frame_ub_l[], + unsigned int dpde0_bytes_per_frame_ub_c[], + int meta_pte_bytes_per_frame_ub_l[], + int meta_pte_bytes_per_frame_ub_c[], + double TimePerVMGroupVBlank[], + double TimePerVMGroupFlip[], + double TimePerVMRequestVBlank[], + double TimePerVMRequestFlip[]) +{ + int num_group_per_lower_vm_stage; + int num_req_per_lower_vm_stage; + int k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (GPUVMEnable == true && (DCCEnable[k] == true || GPUVMMaxPageTableLevels > 1)) { + if (DCCEnable[k] == false) { + if (BytePerPixelC[k] > 0) { + num_group_per_lower_vm_stage = dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (dpde0_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } else { + if (GPUVMMaxPageTableLevels == 1) { + if (BytePerPixelC[k] > 0) { + num_group_per_lower_vm_stage = dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } else { + if (BytePerPixelC[k] > 0) { + num_group_per_lower_vm_stage = 2 + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (dpde0_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = 1 + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } + } + + if (DCCEnable[k] == false) { + if (BytePerPixelC[k] > 0) { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64 + dpde0_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64; + } + } else { + if (GPUVMMaxPageTableLevels == 1) { + if (BytePerPixelC[k] > 0) { + num_req_per_lower_vm_stage = meta_pte_bytes_per_frame_ub_l[k] / 64 + meta_pte_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = meta_pte_bytes_per_frame_ub_l[k] / 64; + } + } else { + if (BytePerPixelC[k] > 0) { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64 + dpde0_bytes_per_frame_ub_c[k] / 64 + + meta_pte_bytes_per_frame_ub_l[k] / 64 + meta_pte_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64 + meta_pte_bytes_per_frame_ub_l[k] / 64; + } + } + } + + TimePerVMGroupVBlank[k] = DestinationLinesToRequestVMInVBlank[k] * HTotal[k] / PixelClock[k] / num_group_per_lower_vm_stage; + TimePerVMGroupFlip[k] = DestinationLinesToRequestVMInImmediateFlip[k] * HTotal[k] / PixelClock[k] / num_group_per_lower_vm_stage; + TimePerVMRequestVBlank[k] = DestinationLinesToRequestVMInVBlank[k] * HTotal[k] / PixelClock[k] / num_req_per_lower_vm_stage; + TimePerVMRequestFlip[k] = DestinationLinesToRequestVMInImmediateFlip[k] * HTotal[k] / PixelClock[k] / num_req_per_lower_vm_stage; + + if (GPUVMMaxPageTableLevels > 2) { + TimePerVMGroupVBlank[k] = TimePerVMGroupVBlank[k] / 2; + TimePerVMGroupFlip[k] = TimePerVMGroupFlip[k] / 2; + TimePerVMRequestVBlank[k] = TimePerVMRequestVBlank[k] / 2; + TimePerVMRequestFlip[k] = TimePerVMRequestFlip[k] / 2; + } + + } else { + TimePerVMGroupVBlank[k] = 0; + TimePerVMGroupFlip[k] = 0; + TimePerVMRequestVBlank[k] = 0; + TimePerVMRequestFlip[k] = 0; + } + } +} + +static void CalculateStutterEfficiency( + struct display_mode_lib *mode_lib, + int CompressedBufferSizeInkByte, + bool UnboundedRequestEnabled, + int ConfigReturnBufferSizeInKByte, + int MetaFIFOSizeInKEntries, + int ZeroSizeBufferEntries, + int NumberOfActivePlanes, + int ROBBufferSizeInKByte, + double TotalDataReadBandwidth, + double DCFCLK, + double ReturnBW, + double COMPBUF_RESERVED_SPACE_64B, + double COMPBUF_RESERVED_SPACE_ZS, + double SRExitTime, + double SRExitZ8Time, + bool SynchronizedVBlank, + double Z8StutterEnterPlusExitWatermark, + double StutterEnterPlusExitWatermark, + bool ProgressiveToInterlaceUnitInOPP, + bool Interlace[], + double MinTTUVBlank[], + int DPPPerPlane[], + unsigned int DETBufferSizeY[], + int BytePerPixelY[], + double BytePerPixelDETY[], + double SwathWidthY[], + int SwathHeightY[], + int SwathHeightC[], + double NetDCCRateLuma[], + double NetDCCRateChroma[], + double DCCFractionOfZeroSizeRequestsLuma[], + double DCCFractionOfZeroSizeRequestsChroma[], + int HTotal[], + int VTotal[], + double PixelClock[], + double VRatio[], + enum scan_direction_class SourceScan[], + int BlockHeight256BytesY[], + int BlockWidth256BytesY[], + int BlockHeight256BytesC[], + int BlockWidth256BytesC[], + int DCCYMaxUncompressedBlock[], + int DCCCMaxUncompressedBlock[], + int VActive[], + bool DCCEnable[], + bool WritebackEnable[], + double ReadBandwidthPlaneLuma[], + double ReadBandwidthPlaneChroma[], + double meta_row_bw[], + double dpte_row_bw[], + double *StutterEfficiencyNotIncludingVBlank, + double *StutterEfficiency, + int *NumberOfStutterBurstsPerFrame, + double *Z8StutterEfficiencyNotIncludingVBlank, + double *Z8StutterEfficiency, + int *Z8NumberOfStutterBurstsPerFrame, + double *StutterPeriod) +{ + struct vba_vars_st *v = &mode_lib->vba; + + double DETBufferingTimeY; + double SwathWidthYCriticalPlane = 0; + double VActiveTimeCriticalPlane = 0; + double FrameTimeCriticalPlane = 0; + int BytePerPixelYCriticalPlane = 0; + double LinesToFinishSwathTransferStutterCriticalPlane = 0; + double MinTTUVBlankCriticalPlane = 0; + double TotalCompressedReadBandwidth; + double TotalRowReadBandwidth; + double AverageDCCCompressionRate; + double EffectiveCompressedBufferSize; + double PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer; + double StutterBurstTime; + int TotalActiveWriteback; + double LinesInDETY; + double LinesInDETYRoundedDownToSwath; + double MaximumEffectiveCompressionLuma; + double MaximumEffectiveCompressionChroma; + double TotalZeroSizeRequestReadBandwidth; + double TotalZeroSizeCompressedReadBandwidth; + double AverageDCCZeroSizeFraction; + double AverageZeroSizeCompressionRate; + int TotalNumberOfActiveOTG = 0; + double LastStutterPeriod = 0.0; + double LastZ8StutterPeriod = 0.0; + int k; + + TotalZeroSizeRequestReadBandwidth = 0; + TotalZeroSizeCompressedReadBandwidth = 0; + TotalRowReadBandwidth = 0; + TotalCompressedReadBandwidth = 0; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (DCCEnable[k] == true) { + if ((SourceScan[k] == dm_vert && BlockWidth256BytesY[k] > SwathHeightY[k]) || (SourceScan[k] != dm_vert && BlockHeight256BytesY[k] > SwathHeightY[k]) + || DCCYMaxUncompressedBlock[k] < 256) { + MaximumEffectiveCompressionLuma = 2; + } else { + MaximumEffectiveCompressionLuma = 4; + } + TotalCompressedReadBandwidth = TotalCompressedReadBandwidth + ReadBandwidthPlaneLuma[k] / dml_min(NetDCCRateLuma[k], MaximumEffectiveCompressionLuma); + TotalZeroSizeRequestReadBandwidth = TotalZeroSizeRequestReadBandwidth + ReadBandwidthPlaneLuma[k] * DCCFractionOfZeroSizeRequestsLuma[k]; + TotalZeroSizeCompressedReadBandwidth = TotalZeroSizeCompressedReadBandwidth + + ReadBandwidthPlaneLuma[k] * DCCFractionOfZeroSizeRequestsLuma[k] / MaximumEffectiveCompressionLuma; + if (ReadBandwidthPlaneChroma[k] > 0) { + if ((SourceScan[k] == dm_vert && BlockWidth256BytesC[k] > SwathHeightC[k]) + || (SourceScan[k] != dm_vert && BlockHeight256BytesC[k] > SwathHeightC[k]) || DCCCMaxUncompressedBlock[k] < 256) { + MaximumEffectiveCompressionChroma = 2; + } else { + MaximumEffectiveCompressionChroma = 4; + } + TotalCompressedReadBandwidth = TotalCompressedReadBandwidth + + ReadBandwidthPlaneChroma[k] / dml_min(NetDCCRateChroma[k], MaximumEffectiveCompressionChroma); + TotalZeroSizeRequestReadBandwidth = TotalZeroSizeRequestReadBandwidth + ReadBandwidthPlaneChroma[k] * DCCFractionOfZeroSizeRequestsChroma[k]; + TotalZeroSizeCompressedReadBandwidth = TotalZeroSizeCompressedReadBandwidth + + ReadBandwidthPlaneChroma[k] * DCCFractionOfZeroSizeRequestsChroma[k] / MaximumEffectiveCompressionChroma; + } + } else { + TotalCompressedReadBandwidth = TotalCompressedReadBandwidth + ReadBandwidthPlaneLuma[k] + ReadBandwidthPlaneChroma[k]; + } + TotalRowReadBandwidth = TotalRowReadBandwidth + DPPPerPlane[k] * (meta_row_bw[k] + dpte_row_bw[k]); + } + + AverageDCCCompressionRate = TotalDataReadBandwidth / TotalCompressedReadBandwidth; + AverageDCCZeroSizeFraction = TotalZeroSizeRequestReadBandwidth / TotalDataReadBandwidth; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: TotalCompressedReadBandwidth = %f\n", __func__, TotalCompressedReadBandwidth); + dml_print("DML::%s: TotalZeroSizeRequestReadBandwidth = %f\n", __func__, TotalZeroSizeRequestReadBandwidth); + dml_print("DML::%s: TotalZeroSizeCompressedReadBandwidth = %f\n", __func__, TotalZeroSizeCompressedReadBandwidth); + dml_print("DML::%s: MaximumEffectiveCompressionLuma = %f\n", __func__, MaximumEffectiveCompressionLuma); + dml_print("DML::%s: MaximumEffectiveCompressionChroma = %f\n", __func__, MaximumEffectiveCompressionChroma); + dml_print("DML::%s: AverageDCCCompressionRate = %f\n", __func__, AverageDCCCompressionRate); + dml_print("DML::%s: AverageDCCZeroSizeFraction = %f\n", __func__, AverageDCCZeroSizeFraction); + dml_print("DML::%s: CompressedBufferSizeInkByte = %d\n", __func__, CompressedBufferSizeInkByte); +#endif + + if (AverageDCCZeroSizeFraction == 1) { + AverageZeroSizeCompressionRate = TotalZeroSizeRequestReadBandwidth / TotalZeroSizeCompressedReadBandwidth; + EffectiveCompressedBufferSize = MetaFIFOSizeInKEntries * 1024 * 64 * AverageZeroSizeCompressionRate + (ZeroSizeBufferEntries - COMPBUF_RESERVED_SPACE_ZS) * 64 * AverageZeroSizeCompressionRate; + } else if (AverageDCCZeroSizeFraction > 0) { + AverageZeroSizeCompressionRate = TotalZeroSizeRequestReadBandwidth / TotalZeroSizeCompressedReadBandwidth; + EffectiveCompressedBufferSize = dml_min( + CompressedBufferSizeInkByte * 1024 * AverageDCCCompressionRate, + MetaFIFOSizeInKEntries * 1024 * 64 / (AverageDCCZeroSizeFraction / AverageZeroSizeCompressionRate + 1 / AverageDCCCompressionRate)) + + dml_min((ROBBufferSizeInKByte * 1024 - COMPBUF_RESERVED_SPACE_64B * 64) * AverageDCCCompressionRate, + (ZeroSizeBufferEntries - COMPBUF_RESERVED_SPACE_ZS) * 64 / (AverageDCCZeroSizeFraction / AverageZeroSizeCompressionRate)); + dml_print("DML::%s: min 1 = %f\n", __func__, CompressedBufferSizeInkByte * 1024 * AverageDCCCompressionRate); + dml_print( + "DML::%s: min 2 = %f\n", + __func__, + MetaFIFOSizeInKEntries * 1024 * 64 / (AverageDCCZeroSizeFraction / AverageZeroSizeCompressionRate + 1 / AverageDCCCompressionRate)); + dml_print("DML::%s: min 3 = %f\n", __func__, ROBBufferSizeInKByte * 1024 * AverageDCCCompressionRate); + dml_print("DML::%s: min 4 = %f\n", __func__, ZeroSizeBufferEntries * 64 / (AverageDCCZeroSizeFraction / AverageZeroSizeCompressionRate)); + } else { + EffectiveCompressedBufferSize = dml_min( + CompressedBufferSizeInkByte * 1024 * AverageDCCCompressionRate, + MetaFIFOSizeInKEntries * 1024 * 64 * AverageDCCCompressionRate) + (ROBBufferSizeInKByte * 1024 - COMPBUF_RESERVED_SPACE_64B * 64) * AverageDCCCompressionRate; + dml_print("DML::%s: min 1 = %f\n", __func__, CompressedBufferSizeInkByte * 1024 * AverageDCCCompressionRate); + dml_print("DML::%s: min 2 = %f\n", __func__, MetaFIFOSizeInKEntries * 1024 * 64 * AverageDCCCompressionRate); + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: MetaFIFOSizeInKEntries = %d\n", __func__, MetaFIFOSizeInKEntries); + dml_print("DML::%s: AverageZeroSizeCompressionRate = %f\n", __func__, AverageZeroSizeCompressionRate); + dml_print("DML::%s: EffectiveCompressedBufferSize = %f\n", __func__, EffectiveCompressedBufferSize); +#endif + + *StutterPeriod = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + LinesInDETY = (DETBufferSizeY[k] + (UnboundedRequestEnabled == true ? EffectiveCompressedBufferSize : 0) * ReadBandwidthPlaneLuma[k] / TotalDataReadBandwidth) + / BytePerPixelDETY[k] / SwathWidthY[k]; + LinesInDETYRoundedDownToSwath = dml_floor(LinesInDETY, SwathHeightY[k]); + DETBufferingTimeY = LinesInDETYRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatio[k]; +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%0d DETBufferSizeY = %f\n", __func__, k, DETBufferSizeY[k]); + dml_print("DML::%s: k=%0d BytePerPixelDETY = %f\n", __func__, k, BytePerPixelDETY[k]); + dml_print("DML::%s: k=%0d SwathWidthY = %f\n", __func__, k, SwathWidthY[k]); + dml_print("DML::%s: k=%0d ReadBandwidthPlaneLuma = %f\n", __func__, k, ReadBandwidthPlaneLuma[k]); + dml_print("DML::%s: k=%0d TotalDataReadBandwidth = %f\n", __func__, k, TotalDataReadBandwidth); + dml_print("DML::%s: k=%0d LinesInDETY = %f\n", __func__, k, LinesInDETY); + dml_print("DML::%s: k=%0d LinesInDETYRoundedDownToSwath = %f\n", __func__, k, LinesInDETYRoundedDownToSwath); + dml_print("DML::%s: k=%0d HTotal = %d\n", __func__, k, HTotal[k]); + dml_print("DML::%s: k=%0d PixelClock = %f\n", __func__, k, PixelClock[k]); + dml_print("DML::%s: k=%0d VRatio = %f\n", __func__, k, VRatio[k]); + dml_print("DML::%s: k=%0d DETBufferingTimeY = %f\n", __func__, k, DETBufferingTimeY); + dml_print("DML::%s: k=%0d PixelClock = %f\n", __func__, k, PixelClock[k]); +#endif + + if (k == 0 || DETBufferingTimeY < *StutterPeriod) { + bool isInterlaceTiming = Interlace[k] && !ProgressiveToInterlaceUnitInOPP; + + *StutterPeriod = DETBufferingTimeY; + FrameTimeCriticalPlane = (isInterlaceTiming ? dml_floor(VTotal[k] / 2.0, 1.0) : VTotal[k]) * HTotal[k] / PixelClock[k]; + VActiveTimeCriticalPlane = (isInterlaceTiming ? dml_floor(VActive[k] / 2.0, 1.0) : VActive[k]) * HTotal[k] / PixelClock[k]; + BytePerPixelYCriticalPlane = BytePerPixelY[k]; + SwathWidthYCriticalPlane = SwathWidthY[k]; + LinesToFinishSwathTransferStutterCriticalPlane = SwathHeightY[k] - (LinesInDETY - LinesInDETYRoundedDownToSwath); + MinTTUVBlankCriticalPlane = MinTTUVBlank[k]; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: StutterPeriod = %f\n", __func__, *StutterPeriod); + dml_print("DML::%s: MinTTUVBlankCriticalPlane = %f\n", __func__, MinTTUVBlankCriticalPlane); + dml_print("DML::%s: FrameTimeCriticalPlane = %f\n", __func__, FrameTimeCriticalPlane); + dml_print("DML::%s: VActiveTimeCriticalPlane = %f\n", __func__, VActiveTimeCriticalPlane); + dml_print("DML::%s: BytePerPixelYCriticalPlane = %d\n", __func__, BytePerPixelYCriticalPlane); + dml_print("DML::%s: SwathWidthYCriticalPlane = %f\n", __func__, SwathWidthYCriticalPlane); + dml_print("DML::%s: LinesToFinishSwathTransferStutterCriticalPlane = %f\n", __func__, LinesToFinishSwathTransferStutterCriticalPlane); +#endif + } + } + + PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer = dml_min(*StutterPeriod * TotalDataReadBandwidth, EffectiveCompressedBufferSize); +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: ROBBufferSizeInKByte = %d\n", __func__, ROBBufferSizeInKByte); + dml_print("DML::%s: AverageDCCCompressionRate = %f\n", __func__, AverageDCCCompressionRate); + dml_print("DML::%s: StutterPeriod * TotalDataReadBandwidth = %f\n", __func__, *StutterPeriod * TotalDataReadBandwidth); + dml_print("DML::%s: ROBBufferSizeInKByte * 1024 * AverageDCCCompressionRate + EffectiveCompressedBufferSize = %f\n", __func__, ROBBufferSizeInKByte * 1024 * AverageDCCCompressionRate + EffectiveCompressedBufferSize); + dml_print("DML::%s: EffectiveCompressedBufferSize = %f\n", __func__, EffectiveCompressedBufferSize); + dml_print("DML::%s: PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer = %f\n", __func__, PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer); + dml_print("DML::%s: ReturnBW = %f\n", __func__, ReturnBW); + dml_print("DML::%s: TotalDataReadBandwidth = %f\n", __func__, TotalDataReadBandwidth); + dml_print("DML::%s: TotalRowReadBandwidth = %f\n", __func__, TotalRowReadBandwidth); + dml_print("DML::%s: DCFCLK = %f\n", __func__, DCFCLK); +#endif + + StutterBurstTime = PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer / AverageDCCCompressionRate / ReturnBW + + (*StutterPeriod * TotalDataReadBandwidth - PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer) / (DCFCLK * 64) + + *StutterPeriod * TotalRowReadBandwidth / ReturnBW; +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: Part 1 = %f\n", __func__, PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer / AverageDCCCompressionRate / ReturnBW); + dml_print("DML::%s: StutterPeriod * TotalDataReadBandwidth = %f\n", __func__, (*StutterPeriod * TotalDataReadBandwidth)); + dml_print("DML::%s: Part 2 = %f\n", __func__, (*StutterPeriod * TotalDataReadBandwidth - PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer) / (DCFCLK * 64)); + dml_print("DML::%s: Part 3 = %f\n", __func__, *StutterPeriod * TotalRowReadBandwidth / ReturnBW); + dml_print("DML::%s: StutterBurstTime = %f\n", __func__, StutterBurstTime); +#endif + StutterBurstTime = dml_max(StutterBurstTime, LinesToFinishSwathTransferStutterCriticalPlane * BytePerPixelYCriticalPlane * SwathWidthYCriticalPlane / ReturnBW); + + dml_print( + "DML::%s: Time to finish residue swath=%f\n", + __func__, + LinesToFinishSwathTransferStutterCriticalPlane * BytePerPixelYCriticalPlane * SwathWidthYCriticalPlane / ReturnBW); + + TotalActiveWriteback = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (WritebackEnable[k]) { + TotalActiveWriteback = TotalActiveWriteback + 1; + } + } + + if (TotalActiveWriteback == 0) { +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: SRExitTime = %f\n", __func__, SRExitTime); + dml_print("DML::%s: SRExitZ8Time = %f\n", __func__, SRExitZ8Time); + dml_print("DML::%s: StutterBurstTime = %f (final)\n", __func__, StutterBurstTime); + dml_print("DML::%s: StutterPeriod = %f\n", __func__, *StutterPeriod); +#endif + *StutterEfficiencyNotIncludingVBlank = dml_max(0., 1 - (SRExitTime + StutterBurstTime) / *StutterPeriod) * 100; + *Z8StutterEfficiencyNotIncludingVBlank = dml_max(0., 1 - (SRExitZ8Time + StutterBurstTime) / *StutterPeriod) * 100; + *NumberOfStutterBurstsPerFrame = (*StutterEfficiencyNotIncludingVBlank > 0 ? dml_ceil(VActiveTimeCriticalPlane / *StutterPeriod, 1) : 0); + *Z8NumberOfStutterBurstsPerFrame = (*Z8StutterEfficiencyNotIncludingVBlank > 0 ? dml_ceil(VActiveTimeCriticalPlane / *StutterPeriod, 1) : 0); + } else { + *StutterEfficiencyNotIncludingVBlank = 0.; + *Z8StutterEfficiencyNotIncludingVBlank = 0.; + *NumberOfStutterBurstsPerFrame = 0; + *Z8NumberOfStutterBurstsPerFrame = 0; + } +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: VActiveTimeCriticalPlane = %f\n", __func__, VActiveTimeCriticalPlane); + dml_print("DML::%s: StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *StutterEfficiencyNotIncludingVBlank); + dml_print("DML::%s: Z8StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *Z8StutterEfficiencyNotIncludingVBlank); + dml_print("DML::%s: NumberOfStutterBurstsPerFrame = %d\n", __func__, *NumberOfStutterBurstsPerFrame); + dml_print("DML::%s: Z8NumberOfStutterBurstsPerFrame = %d\n", __func__, *Z8NumberOfStutterBurstsPerFrame); +#endif + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k) { + TotalNumberOfActiveOTG = TotalNumberOfActiveOTG + 1; + } + } + + if (*StutterEfficiencyNotIncludingVBlank > 0) { + LastStutterPeriod = VActiveTimeCriticalPlane - (*NumberOfStutterBurstsPerFrame - 1) * *StutterPeriod; + + if ((SynchronizedVBlank || TotalNumberOfActiveOTG == 1) && LastStutterPeriod + MinTTUVBlankCriticalPlane > StutterEnterPlusExitWatermark) { + *StutterEfficiency = (1 - (*NumberOfStutterBurstsPerFrame * SRExitTime + StutterBurstTime * VActiveTimeCriticalPlane + / *StutterPeriod) / FrameTimeCriticalPlane) * 100; + } else { + *StutterEfficiency = *StutterEfficiencyNotIncludingVBlank; + } + } else { + *StutterEfficiency = 0; + } + + if (*Z8StutterEfficiencyNotIncludingVBlank > 0) { + LastZ8StutterPeriod = VActiveTimeCriticalPlane - (*NumberOfStutterBurstsPerFrame - 1) * *StutterPeriod; + if ((SynchronizedVBlank || TotalNumberOfActiveOTG == 1) && LastZ8StutterPeriod + MinTTUVBlankCriticalPlane > Z8StutterEnterPlusExitWatermark) { + *Z8StutterEfficiency = (1 - (*NumberOfStutterBurstsPerFrame * SRExitZ8Time + StutterBurstTime * VActiveTimeCriticalPlane + / *StutterPeriod) / FrameTimeCriticalPlane) * 100; + } else { + *Z8StutterEfficiency = *Z8StutterEfficiencyNotIncludingVBlank; + } + } else { + *Z8StutterEfficiency = 0.; + } + + dml_print("DML::%s: LastZ8StutterPeriod = %f\n", __func__, LastZ8StutterPeriod); + dml_print("DML::%s: Z8StutterEnterPlusExitWatermark = %f\n", __func__, Z8StutterEnterPlusExitWatermark); + dml_print("DML::%s: StutterBurstTime = %f\n", __func__, StutterBurstTime); + dml_print("DML::%s: StutterPeriod = %f\n", __func__, *StutterPeriod); + dml_print("DML::%s: StutterEfficiency = %f\n", __func__, *StutterEfficiency); + dml_print("DML::%s: Z8StutterEfficiency = %f\n", __func__, *Z8StutterEfficiency); + dml_print("DML::%s: StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *StutterEfficiencyNotIncludingVBlank); + dml_print("DML::%s: Z8NumberOfStutterBurstsPerFrame = %d\n", __func__, *Z8NumberOfStutterBurstsPerFrame); +} + +static void CalculateSwathAndDETConfiguration( + bool ForceSingleDPP, + int NumberOfActivePlanes, + unsigned int DETBufferSizeInKByte, + double MaximumSwathWidthLuma[], + double MaximumSwathWidthChroma[], + enum scan_direction_class SourceScan[], + enum source_format_class SourcePixelFormat[], + enum dm_swizzle_mode SurfaceTiling[], + int ViewportWidth[], + int ViewportHeight[], + int SurfaceWidthY[], + int SurfaceWidthC[], + int SurfaceHeightY[], + int SurfaceHeightC[], + int Read256BytesBlockHeightY[], + int Read256BytesBlockHeightC[], + int Read256BytesBlockWidthY[], + int Read256BytesBlockWidthC[], + enum odm_combine_mode ODMCombineEnabled[], + int BlendingAndTiming[], + int BytePerPixY[], + int BytePerPixC[], + double BytePerPixDETY[], + double BytePerPixDETC[], + int HActive[], + double HRatio[], + double HRatioChroma[], + int DPPPerPlane[], + int swath_width_luma_ub[], + int swath_width_chroma_ub[], + double SwathWidth[], + double SwathWidthChroma[], + int SwathHeightY[], + int SwathHeightC[], + unsigned int DETBufferSizeY[], + unsigned int DETBufferSizeC[], + bool ViewportSizeSupportPerPlane[], + bool *ViewportSizeSupport) +{ + int MaximumSwathHeightY[DC__NUM_DPP__MAX]; + int MaximumSwathHeightC[DC__NUM_DPP__MAX]; + int MinimumSwathHeightY; + int MinimumSwathHeightC; + int RoundedUpMaxSwathSizeBytesY; + int RoundedUpMaxSwathSizeBytesC; + int RoundedUpMinSwathSizeBytesY; + int RoundedUpMinSwathSizeBytesC; + int RoundedUpSwathSizeBytesY; + int RoundedUpSwathSizeBytesC; + double SwathWidthSingleDPP[DC__NUM_DPP__MAX]; + double SwathWidthSingleDPPChroma[DC__NUM_DPP__MAX]; + int k; + + CalculateSwathWidth( + ForceSingleDPP, + NumberOfActivePlanes, + SourcePixelFormat, + SourceScan, + ViewportWidth, + ViewportHeight, + SurfaceWidthY, + SurfaceWidthC, + SurfaceHeightY, + SurfaceHeightC, + ODMCombineEnabled, + BytePerPixY, + BytePerPixC, + Read256BytesBlockHeightY, + Read256BytesBlockHeightC, + Read256BytesBlockWidthY, + Read256BytesBlockWidthC, + BlendingAndTiming, + HActive, + HRatio, + DPPPerPlane, + SwathWidthSingleDPP, + SwathWidthSingleDPPChroma, + SwathWidth, + SwathWidthChroma, + MaximumSwathHeightY, + MaximumSwathHeightC, + swath_width_luma_ub, + swath_width_chroma_ub); + + *ViewportSizeSupport = true; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if ((SourcePixelFormat[k] == dm_444_64 || SourcePixelFormat[k] == dm_444_32 || SourcePixelFormat[k] == dm_444_16 || SourcePixelFormat[k] == dm_mono_16 + || SourcePixelFormat[k] == dm_mono_8 || SourcePixelFormat[k] == dm_rgbe)) { + if (SurfaceTiling[k] == dm_sw_linear + || (SourcePixelFormat[k] == dm_444_64 + && (SurfaceTiling[k] == dm_sw_64kb_s || SurfaceTiling[k] == dm_sw_64kb_s_t || SurfaceTiling[k] == dm_sw_64kb_s_x) + && SourceScan[k] != dm_vert)) { + MinimumSwathHeightY = MaximumSwathHeightY[k]; + } else if (SourcePixelFormat[k] == dm_444_8 && SourceScan[k] == dm_vert) { + MinimumSwathHeightY = MaximumSwathHeightY[k]; + } else { + MinimumSwathHeightY = MaximumSwathHeightY[k] / 2; + } + MinimumSwathHeightC = MaximumSwathHeightC[k]; + } else { + if (SurfaceTiling[k] == dm_sw_linear) { + MinimumSwathHeightY = MaximumSwathHeightY[k]; + MinimumSwathHeightC = MaximumSwathHeightC[k]; + } else if (SourcePixelFormat[k] == dm_rgbe_alpha && SourceScan[k] == dm_vert) { + MinimumSwathHeightY = MaximumSwathHeightY[k] / 2; + MinimumSwathHeightC = MaximumSwathHeightC[k]; + } else if (SourcePixelFormat[k] == dm_rgbe_alpha) { + MinimumSwathHeightY = MaximumSwathHeightY[k] / 2; + MinimumSwathHeightC = MaximumSwathHeightC[k] / 2; + } else if (SourcePixelFormat[k] == dm_420_8 && SourceScan[k] == dm_vert) { + MinimumSwathHeightY = MaximumSwathHeightY[k]; + MinimumSwathHeightC = MaximumSwathHeightC[k] / 2; + } else { + MinimumSwathHeightC = MaximumSwathHeightC[k] / 2; + MinimumSwathHeightY = MaximumSwathHeightY[k] / 2; + } + } + + RoundedUpMaxSwathSizeBytesY = swath_width_luma_ub[k] * BytePerPixDETY[k] * MaximumSwathHeightY[k]; + RoundedUpMinSwathSizeBytesY = swath_width_luma_ub[k] * BytePerPixDETY[k] * MinimumSwathHeightY; + if (SourcePixelFormat[k] == dm_420_10) { + RoundedUpMaxSwathSizeBytesY = dml_ceil((double) RoundedUpMaxSwathSizeBytesY, 256); + RoundedUpMinSwathSizeBytesY = dml_ceil((double) RoundedUpMinSwathSizeBytesY, 256); + } + RoundedUpMaxSwathSizeBytesC = swath_width_chroma_ub[k] * BytePerPixDETC[k] * MaximumSwathHeightC[k]; + RoundedUpMinSwathSizeBytesC = swath_width_chroma_ub[k] * BytePerPixDETC[k] * MinimumSwathHeightC; + if (SourcePixelFormat[k] == dm_420_10) { + RoundedUpMaxSwathSizeBytesC = dml_ceil(RoundedUpMaxSwathSizeBytesC, 256); + RoundedUpMinSwathSizeBytesC = dml_ceil(RoundedUpMinSwathSizeBytesC, 256); + } + + if (RoundedUpMaxSwathSizeBytesY + RoundedUpMaxSwathSizeBytesC <= DETBufferSizeInKByte * 1024 / 2) { + SwathHeightY[k] = MaximumSwathHeightY[k]; + SwathHeightC[k] = MaximumSwathHeightC[k]; + RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY; + RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC; + } else if (RoundedUpMaxSwathSizeBytesY >= 1.5 * RoundedUpMaxSwathSizeBytesC + && RoundedUpMinSwathSizeBytesY + RoundedUpMaxSwathSizeBytesC <= DETBufferSizeInKByte * 1024 / 2) { + SwathHeightY[k] = MinimumSwathHeightY; + SwathHeightC[k] = MaximumSwathHeightC[k]; + RoundedUpSwathSizeBytesY = RoundedUpMinSwathSizeBytesY; + RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC; + } else if (RoundedUpMaxSwathSizeBytesY < 1.5 * RoundedUpMaxSwathSizeBytesC + && RoundedUpMaxSwathSizeBytesY + RoundedUpMinSwathSizeBytesC <= DETBufferSizeInKByte * 1024 / 2) { + SwathHeightY[k] = MaximumSwathHeightY[k]; + SwathHeightC[k] = MinimumSwathHeightC; + RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY; + RoundedUpSwathSizeBytesC = RoundedUpMinSwathSizeBytesC; + } else { + SwathHeightY[k] = MinimumSwathHeightY; + SwathHeightC[k] = MinimumSwathHeightC; + RoundedUpSwathSizeBytesY = RoundedUpMinSwathSizeBytesY; + RoundedUpSwathSizeBytesC = RoundedUpMinSwathSizeBytesC; + } + { + double actDETBufferSizeInKByte = dml_ceil(DETBufferSizeInKByte, 64); + if (SwathHeightC[k] == 0) { + DETBufferSizeY[k] = actDETBufferSizeInKByte * 1024; + DETBufferSizeC[k] = 0; + } else if (RoundedUpSwathSizeBytesY <= 1.5 * RoundedUpSwathSizeBytesC) { + DETBufferSizeY[k] = actDETBufferSizeInKByte * 1024 / 2; + DETBufferSizeC[k] = actDETBufferSizeInKByte * 1024 / 2; + } else { + DETBufferSizeY[k] = dml_floor(actDETBufferSizeInKByte * 1024 * 2 / 3, 1024); + DETBufferSizeC[k] = actDETBufferSizeInKByte * 1024 / 3; + } + + if (RoundedUpMinSwathSizeBytesY + RoundedUpMinSwathSizeBytesC > actDETBufferSizeInKByte * 1024 / 2 || SwathWidth[k] > MaximumSwathWidthLuma[k] + || (SwathHeightC[k] > 0 && SwathWidthChroma[k] > MaximumSwathWidthChroma[k])) { + *ViewportSizeSupport = false; + ViewportSizeSupportPerPlane[k] = false; + } else { + ViewportSizeSupportPerPlane[k] = true; + } + } + } +} + +static void CalculateSwathWidth( + bool ForceSingleDPP, + int NumberOfActivePlanes, + enum source_format_class SourcePixelFormat[], + enum scan_direction_class SourceScan[], + int ViewportWidth[], + int ViewportHeight[], + int SurfaceWidthY[], + int SurfaceWidthC[], + int SurfaceHeightY[], + int SurfaceHeightC[], + enum odm_combine_mode ODMCombineEnabled[], + int BytePerPixY[], + int BytePerPixC[], + int Read256BytesBlockHeightY[], + int Read256BytesBlockHeightC[], + int Read256BytesBlockWidthY[], + int Read256BytesBlockWidthC[], + int BlendingAndTiming[], + int HActive[], + double HRatio[], + int DPPPerPlane[], + double SwathWidthSingleDPPY[], + double SwathWidthSingleDPPC[], + double SwathWidthY[], + double SwathWidthC[], + int MaximumSwathHeightY[], + int MaximumSwathHeightC[], + int swath_width_luma_ub[], + int swath_width_chroma_ub[]) +{ + enum odm_combine_mode MainPlaneODMCombine; + int j, k; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: NumberOfActivePlanes = %d\n", __func__, NumberOfActivePlanes); +#endif + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (SourceScan[k] != dm_vert) { + SwathWidthSingleDPPY[k] = ViewportWidth[k]; + } else { + SwathWidthSingleDPPY[k] = ViewportHeight[k]; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d ViewportWidth=%d\n", __func__, k, ViewportWidth[k]); + dml_print("DML::%s: k=%d ViewportHeight=%d\n", __func__, k, ViewportHeight[k]); +#endif + + MainPlaneODMCombine = ODMCombineEnabled[k]; + for (j = 0; j < NumberOfActivePlanes; ++j) { + if (BlendingAndTiming[k] == j) { + MainPlaneODMCombine = ODMCombineEnabled[j]; + } + } + + if (MainPlaneODMCombine == dm_odm_combine_mode_4to1) { + SwathWidthY[k] = dml_min(SwathWidthSingleDPPY[k], dml_round(HActive[k] / 4.0 * HRatio[k])); + } else if (MainPlaneODMCombine == dm_odm_combine_mode_2to1) { + SwathWidthY[k] = dml_min(SwathWidthSingleDPPY[k], dml_round(HActive[k] / 2.0 * HRatio[k])); + } else if (DPPPerPlane[k] == 2) { + SwathWidthY[k] = SwathWidthSingleDPPY[k] / 2; + } else { + SwathWidthY[k] = SwathWidthSingleDPPY[k]; + } + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d SwathWidthSingleDPPY=%f\n", __func__, k, SwathWidthSingleDPPY[k]); + dml_print("DML::%s: k=%d SwathWidthY=%f\n", __func__, k, SwathWidthY[k]); +#endif + + if (SourcePixelFormat[k] == dm_420_8 || SourcePixelFormat[k] == dm_420_10 || SourcePixelFormat[k] == dm_420_12) { + SwathWidthC[k] = SwathWidthY[k] / 2; + SwathWidthSingleDPPC[k] = SwathWidthSingleDPPY[k] / 2; + } else { + SwathWidthC[k] = SwathWidthY[k]; + SwathWidthSingleDPPC[k] = SwathWidthSingleDPPY[k]; + } + + if (ForceSingleDPP == true) { + SwathWidthY[k] = SwathWidthSingleDPPY[k]; + SwathWidthC[k] = SwathWidthSingleDPPC[k]; + } + { + int surface_width_ub_l = dml_ceil(SurfaceWidthY[k], Read256BytesBlockWidthY[k]); + int surface_height_ub_l = dml_ceil(SurfaceHeightY[k], Read256BytesBlockHeightY[k]); + int surface_width_ub_c = dml_ceil(SurfaceWidthC[k], Read256BytesBlockWidthC[k]); + int surface_height_ub_c = dml_ceil(SurfaceHeightC[k], Read256BytesBlockHeightC[k]); + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: k=%d surface_width_ub_l=%0d\n", __func__, k, surface_width_ub_l); +#endif + + if (SourceScan[k] != dm_vert) { + MaximumSwathHeightY[k] = Read256BytesBlockHeightY[k]; + MaximumSwathHeightC[k] = Read256BytesBlockHeightC[k]; + swath_width_luma_ub[k] = dml_min(surface_width_ub_l, (int) dml_ceil(SwathWidthY[k] - 1, Read256BytesBlockWidthY[k]) + Read256BytesBlockWidthY[k]); + if (BytePerPixC[k] > 0) { + swath_width_chroma_ub[k] = dml_min( + surface_width_ub_c, + (int) dml_ceil(SwathWidthC[k] - 1, Read256BytesBlockWidthC[k]) + Read256BytesBlockWidthC[k]); + } else { + swath_width_chroma_ub[k] = 0; + } + } else { + MaximumSwathHeightY[k] = Read256BytesBlockWidthY[k]; + MaximumSwathHeightC[k] = Read256BytesBlockWidthC[k]; + swath_width_luma_ub[k] = dml_min(surface_height_ub_l, (int) dml_ceil(SwathWidthY[k] - 1, Read256BytesBlockHeightY[k]) + Read256BytesBlockHeightY[k]); + if (BytePerPixC[k] > 0) { + swath_width_chroma_ub[k] = dml_min( + surface_height_ub_c, + (int) dml_ceil(SwathWidthC[k] - 1, Read256BytesBlockHeightC[k]) + Read256BytesBlockHeightC[k]); + } else { + swath_width_chroma_ub[k] = 0; + } + } + } + } +} + +static double CalculateExtraLatency( + int RoundTripPingLatencyCycles, + int ReorderingBytes, + double DCFCLK, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + double ReturnBW, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + int dpte_group_bytes[], + double HostVMInefficiencyFactor, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels) +{ + double ExtraLatencyBytes; + double ExtraLatency; + + ExtraLatencyBytes = CalculateExtraLatencyBytes( + ReorderingBytes, + TotalNumberOfActiveDPP, + PixelChunkSizeInKByte, + TotalNumberOfDCCActiveDPP, + MetaChunkSize, + GPUVMEnable, + HostVMEnable, + NumberOfActivePlanes, + NumberOfDPP, + dpte_group_bytes, + HostVMInefficiencyFactor, + HostVMMinPageSize, + HostVMMaxNonCachedPageTableLevels); + + ExtraLatency = (RoundTripPingLatencyCycles + __DML_ARB_TO_RET_DELAY__) / DCFCLK + ExtraLatencyBytes / ReturnBW; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: RoundTripPingLatencyCycles=%d\n", __func__, RoundTripPingLatencyCycles); + dml_print("DML::%s: DCFCLK=%f\n", __func__, DCFCLK); + dml_print("DML::%s: ExtraLatencyBytes=%f\n", __func__, ExtraLatencyBytes); + dml_print("DML::%s: ReturnBW=%f\n", __func__, ReturnBW); + dml_print("DML::%s: ExtraLatency=%f\n", __func__, ExtraLatency); +#endif + + return ExtraLatency; +} + +static double CalculateExtraLatencyBytes( + int ReorderingBytes, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + int dpte_group_bytes[], + double HostVMInefficiencyFactor, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels) +{ + double ret; + int HostVMDynamicLevels = 0, k; + + if (GPUVMEnable == true && HostVMEnable == true) { + if (HostVMMinPageSize < 2048) { + HostVMDynamicLevels = HostVMMaxNonCachedPageTableLevels; + } else if (HostVMMinPageSize >= 2048 && HostVMMinPageSize < 1048576) { + HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 1); + } else { + HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 2); + } + } else { + HostVMDynamicLevels = 0; + } + + ret = ReorderingBytes + (TotalNumberOfActiveDPP * PixelChunkSizeInKByte + TotalNumberOfDCCActiveDPP * MetaChunkSize) * 1024.0; + + if (GPUVMEnable == true) { + for (k = 0; k < NumberOfActivePlanes; ++k) { + ret = ret + NumberOfDPP[k] * dpte_group_bytes[k] * (1 + 8 * HostVMDynamicLevels) * HostVMInefficiencyFactor; + } + } + return ret; +} + +static double CalculateUrgentLatency( + double UrgentLatencyPixelDataOnly, + double UrgentLatencyPixelMixedWithVMData, + double UrgentLatencyVMDataOnly, + bool DoUrgentLatencyAdjustment, + double UrgentLatencyAdjustmentFabricClockComponent, + double UrgentLatencyAdjustmentFabricClockReference, + double FabricClock) +{ + double ret; + + ret = dml_max3(UrgentLatencyPixelDataOnly, UrgentLatencyPixelMixedWithVMData, UrgentLatencyVMDataOnly); + if (DoUrgentLatencyAdjustment == true) { + ret = ret + UrgentLatencyAdjustmentFabricClockComponent * (UrgentLatencyAdjustmentFabricClockReference / FabricClock - 1); + } + return ret; +} + +static void UseMinimumDCFCLK( + struct display_mode_lib *mode_lib, + int MaxInterDCNTileRepeaters, + int MaxPrefetchMode, + double FinalDRAMClockChangeLatency, + double SREnterPlusExitTime, + int ReturnBusWidth, + int RoundTripPingLatencyCycles, + int ReorderingBytes, + int PixelChunkSizeInKByte, + int MetaChunkSize, + bool GPUVMEnable, + int GPUVMMaxPageTableLevels, + bool HostVMEnable, + int NumberOfActivePlanes, + double HostVMMinPageSize, + int HostVMMaxNonCachedPageTableLevels, + bool DynamicMetadataVMEnabled, + enum immediate_flip_requirement ImmediateFlipRequirement, + bool ProgressiveToInterlaceUnitInOPP, + double MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation, + double PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency, + int VTotal[], + int VActive[], + int DynamicMetadataTransmittedBytes[], + int DynamicMetadataLinesBeforeActiveRequired[], + bool Interlace[], + double RequiredDPPCLK[][2][DC__NUM_DPP__MAX], + double RequiredDISPCLK[][2], + double UrgLatency[], + unsigned int NoOfDPP[][2][DC__NUM_DPP__MAX], + double ProjectedDCFCLKDeepSleep[][2], + double MaximumVStartup[][2][DC__NUM_DPP__MAX], + double TotalVActivePixelBandwidth[][2], + double TotalVActiveCursorBandwidth[][2], + double TotalMetaRowBandwidth[][2], + double TotalDPTERowBandwidth[][2], + unsigned int TotalNumberOfActiveDPP[][2], + unsigned int TotalNumberOfDCCActiveDPP[][2], + int dpte_group_bytes[], + double PrefetchLinesY[][2][DC__NUM_DPP__MAX], + double PrefetchLinesC[][2][DC__NUM_DPP__MAX], + int swath_width_luma_ub_all_states[][2][DC__NUM_DPP__MAX], + int swath_width_chroma_ub_all_states[][2][DC__NUM_DPP__MAX], + int BytePerPixelY[], + int BytePerPixelC[], + int HTotal[], + double PixelClock[], + double PDEAndMetaPTEBytesPerFrame[][2][DC__NUM_DPP__MAX], + double DPTEBytesPerRow[][2][DC__NUM_DPP__MAX], + double MetaRowBytes[][2][DC__NUM_DPP__MAX], + bool DynamicMetadataEnable[], + double VActivePixelBandwidth[][2][DC__NUM_DPP__MAX], + double VActiveCursorBandwidth[][2][DC__NUM_DPP__MAX], + double ReadBandwidthLuma[], + double ReadBandwidthChroma[], + double DCFCLKPerState[], + double DCFCLKState[][2]) +{ + struct vba_vars_st *v = &mode_lib->vba; + int dummy1, i, j, k; + double NormalEfficiency, dummy2, dummy3; + double TotalMaxPrefetchFlipDPTERowBandwidth[DC__VOLTAGE_STATES][2]; + + NormalEfficiency = PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency / 100.0; + for (i = 0; i < v->soc.num_states; ++i) { + for (j = 0; j <= 1; ++j) { + double PixelDCFCLKCyclesRequiredInPrefetch[DC__NUM_DPP__MAX]; + double PrefetchPixelLinesTime[DC__NUM_DPP__MAX]; + double DCFCLKRequiredForPeakBandwidthPerPlane[DC__NUM_DPP__MAX]; + double DynamicMetadataVMExtraLatency[DC__NUM_DPP__MAX]; + double MinimumTWait; + double NonDPTEBandwidth; + double DPTEBandwidth; + double DCFCLKRequiredForAverageBandwidth; + double ExtraLatencyBytes; + double ExtraLatencyCycles; + double DCFCLKRequiredForPeakBandwidth; + int NoOfDPPState[DC__NUM_DPP__MAX]; + double MinimumTvmPlus2Tr0; + + TotalMaxPrefetchFlipDPTERowBandwidth[i][j] = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + TotalMaxPrefetchFlipDPTERowBandwidth[i][j] = TotalMaxPrefetchFlipDPTERowBandwidth[i][j] + + NoOfDPP[i][j][k] * DPTEBytesPerRow[i][j][k] / (15.75 * HTotal[k] / PixelClock[k]); + } + + for (k = 0; k <= NumberOfActivePlanes - 1; ++k) { + NoOfDPPState[k] = NoOfDPP[i][j][k]; + } + + MinimumTWait = CalculateTWait(MaxPrefetchMode, FinalDRAMClockChangeLatency, UrgLatency[i], SREnterPlusExitTime); + NonDPTEBandwidth = TotalVActivePixelBandwidth[i][j] + TotalVActiveCursorBandwidth[i][j] + TotalMetaRowBandwidth[i][j]; + DPTEBandwidth = (HostVMEnable == true || ImmediateFlipRequirement == dm_immediate_flip_required) ? + TotalMaxPrefetchFlipDPTERowBandwidth[i][j] : TotalDPTERowBandwidth[i][j]; + DCFCLKRequiredForAverageBandwidth = dml_max3( + ProjectedDCFCLKDeepSleep[i][j], + (NonDPTEBandwidth + TotalDPTERowBandwidth[i][j]) / ReturnBusWidth + / (MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation / 100), + (NonDPTEBandwidth + DPTEBandwidth / NormalEfficiency) / NormalEfficiency / ReturnBusWidth); + + ExtraLatencyBytes = CalculateExtraLatencyBytes( + ReorderingBytes, + TotalNumberOfActiveDPP[i][j], + PixelChunkSizeInKByte, + TotalNumberOfDCCActiveDPP[i][j], + MetaChunkSize, + GPUVMEnable, + HostVMEnable, + NumberOfActivePlanes, + NoOfDPPState, + dpte_group_bytes, + 1, + HostVMMinPageSize, + HostVMMaxNonCachedPageTableLevels); + ExtraLatencyCycles = RoundTripPingLatencyCycles + __DML_ARB_TO_RET_DELAY__ + ExtraLatencyBytes / NormalEfficiency / ReturnBusWidth; + for (k = 0; k < NumberOfActivePlanes; ++k) { + double DCFCLKCyclesRequiredInPrefetch; + double ExpectedPrefetchBWAcceleration; + double PrefetchTime; + + PixelDCFCLKCyclesRequiredInPrefetch[k] = (PrefetchLinesY[i][j][k] * swath_width_luma_ub_all_states[i][j][k] * BytePerPixelY[k] + + PrefetchLinesC[i][j][k] * swath_width_chroma_ub_all_states[i][j][k] * BytePerPixelC[k]) / NormalEfficiency / ReturnBusWidth; + DCFCLKCyclesRequiredInPrefetch = 2 * ExtraLatencyCycles / NoOfDPPState[k] + + PDEAndMetaPTEBytesPerFrame[i][j][k] / NormalEfficiency / NormalEfficiency / ReturnBusWidth * (GPUVMMaxPageTableLevels > 2 ? 1 : 0) + + 2 * DPTEBytesPerRow[i][j][k] / NormalEfficiency / NormalEfficiency / ReturnBusWidth + + 2 * MetaRowBytes[i][j][k] / NormalEfficiency / ReturnBusWidth + PixelDCFCLKCyclesRequiredInPrefetch[k]; + PrefetchPixelLinesTime[k] = dml_max(PrefetchLinesY[i][j][k], PrefetchLinesC[i][j][k]) * HTotal[k] / PixelClock[k]; + ExpectedPrefetchBWAcceleration = (VActivePixelBandwidth[i][j][k] + VActiveCursorBandwidth[i][j][k]) + / (ReadBandwidthLuma[k] + ReadBandwidthChroma[k]); + DynamicMetadataVMExtraLatency[k] = + (GPUVMEnable == true && DynamicMetadataEnable[k] == true && DynamicMetadataVMEnabled == true) ? + UrgLatency[i] * GPUVMMaxPageTableLevels * (HostVMEnable == true ? HostVMMaxNonCachedPageTableLevels + 1 : 1) : 0; + PrefetchTime = (MaximumVStartup[i][j][k] - 1) * HTotal[k] / PixelClock[k] - MinimumTWait + - UrgLatency[i] + * ((GPUVMMaxPageTableLevels <= 2 ? GPUVMMaxPageTableLevels : GPUVMMaxPageTableLevels - 2) + * (HostVMEnable == true ? HostVMMaxNonCachedPageTableLevels + 1 : 1) - 1) + - DynamicMetadataVMExtraLatency[k]; + + if (PrefetchTime > 0) { + double ExpectedVRatioPrefetch; + ExpectedVRatioPrefetch = PrefetchPixelLinesTime[k] + / (PrefetchTime * PixelDCFCLKCyclesRequiredInPrefetch[k] / DCFCLKCyclesRequiredInPrefetch); + DCFCLKRequiredForPeakBandwidthPerPlane[k] = NoOfDPPState[k] * PixelDCFCLKCyclesRequiredInPrefetch[k] / PrefetchPixelLinesTime[k] + * dml_max(1.0, ExpectedVRatioPrefetch) * dml_max(1.0, ExpectedVRatioPrefetch / 4) * ExpectedPrefetchBWAcceleration; + if (HostVMEnable == true || ImmediateFlipRequirement == dm_immediate_flip_required) { + DCFCLKRequiredForPeakBandwidthPerPlane[k] = DCFCLKRequiredForPeakBandwidthPerPlane[k] + + NoOfDPPState[k] * DPTEBandwidth / NormalEfficiency / NormalEfficiency / ReturnBusWidth; + } + } else { + DCFCLKRequiredForPeakBandwidthPerPlane[k] = DCFCLKPerState[i]; + } + if (DynamicMetadataEnable[k] == true) { + double TSetupPipe; + double TdmbfPipe; + double TdmsksPipe; + double TdmecPipe; + double AllowedTimeForUrgentExtraLatency; + + CalculateVupdateAndDynamicMetadataParameters( + MaxInterDCNTileRepeaters, + RequiredDPPCLK[i][j][k], + RequiredDISPCLK[i][j], + ProjectedDCFCLKDeepSleep[i][j], + PixelClock[k], + HTotal[k], + VTotal[k] - VActive[k], + DynamicMetadataTransmittedBytes[k], + DynamicMetadataLinesBeforeActiveRequired[k], + Interlace[k], + ProgressiveToInterlaceUnitInOPP, + &TSetupPipe, + &TdmbfPipe, + &TdmecPipe, + &TdmsksPipe, + &dummy1, + &dummy2, + &dummy3); + AllowedTimeForUrgentExtraLatency = MaximumVStartup[i][j][k] * HTotal[k] / PixelClock[k] - MinimumTWait - TSetupPipe - TdmbfPipe - TdmecPipe + - TdmsksPipe - DynamicMetadataVMExtraLatency[k]; + if (AllowedTimeForUrgentExtraLatency > 0) { + DCFCLKRequiredForPeakBandwidthPerPlane[k] = dml_max( + DCFCLKRequiredForPeakBandwidthPerPlane[k], + ExtraLatencyCycles / AllowedTimeForUrgentExtraLatency); + } else { + DCFCLKRequiredForPeakBandwidthPerPlane[k] = DCFCLKPerState[i]; + } + } + } + DCFCLKRequiredForPeakBandwidth = 0; + for (k = 0; k <= NumberOfActivePlanes - 1; ++k) { + DCFCLKRequiredForPeakBandwidth = DCFCLKRequiredForPeakBandwidth + DCFCLKRequiredForPeakBandwidthPerPlane[k]; + } + MinimumTvmPlus2Tr0 = UrgLatency[i] + * (GPUVMEnable == true ? + (HostVMEnable == true ? + (GPUVMMaxPageTableLevels + 2) * (HostVMMaxNonCachedPageTableLevels + 1) - 1 : GPUVMMaxPageTableLevels + 1) : + 0); + for (k = 0; k < NumberOfActivePlanes; ++k) { + double MaximumTvmPlus2Tr0PlusTsw; + MaximumTvmPlus2Tr0PlusTsw = (MaximumVStartup[i][j][k] - 2) * HTotal[k] / PixelClock[k] - MinimumTWait - DynamicMetadataVMExtraLatency[k]; + if (MaximumTvmPlus2Tr0PlusTsw <= MinimumTvmPlus2Tr0 + PrefetchPixelLinesTime[k] / 4) { + DCFCLKRequiredForPeakBandwidth = DCFCLKPerState[i]; + } else { + DCFCLKRequiredForPeakBandwidth = dml_max3( + DCFCLKRequiredForPeakBandwidth, + 2 * ExtraLatencyCycles / (MaximumTvmPlus2Tr0PlusTsw - MinimumTvmPlus2Tr0 - PrefetchPixelLinesTime[k] / 4), + (2 * ExtraLatencyCycles + PixelDCFCLKCyclesRequiredInPrefetch[k]) / (MaximumTvmPlus2Tr0PlusTsw - MinimumTvmPlus2Tr0)); + } + } + DCFCLKState[i][j] = dml_min(DCFCLKPerState[i], 1.05 * dml_max(DCFCLKRequiredForAverageBandwidth, DCFCLKRequiredForPeakBandwidth)); + } + } +} + +static void CalculateUnboundedRequestAndCompressedBufferSize( + unsigned int DETBufferSizeInKByte, + int ConfigReturnBufferSizeInKByte, + enum unbounded_requesting_policy UseUnboundedRequestingFinal, + int TotalActiveDPP, + bool NoChromaPlanes, + int MaxNumDPP, + int CompressedBufferSegmentSizeInkByteFinal, + enum output_encoder_class *Output, + bool *UnboundedRequestEnabled, + int *CompressedBufferSizeInkByte) +{ + double actDETBufferSizeInKByte = dml_ceil(DETBufferSizeInKByte, 64); + + *UnboundedRequestEnabled = UnboundedRequest(UseUnboundedRequestingFinal, TotalActiveDPP, NoChromaPlanes, Output[0]); + *CompressedBufferSizeInkByte = ( + *UnboundedRequestEnabled == true ? + ConfigReturnBufferSizeInKByte - TotalActiveDPP * actDETBufferSizeInKByte : + ConfigReturnBufferSizeInKByte - MaxNumDPP * actDETBufferSizeInKByte); + *CompressedBufferSizeInkByte = *CompressedBufferSizeInkByte * CompressedBufferSegmentSizeInkByteFinal / 64; + +#ifdef __DML_VBA_DEBUG__ + dml_print("DML::%s: TotalActiveDPP = %d\n", __func__, TotalActiveDPP); + dml_print("DML::%s: DETBufferSizeInKByte = %d\n", __func__, DETBufferSizeInKByte); + dml_print("DML::%s: ConfigReturnBufferSizeInKByte = %d\n", __func__, ConfigReturnBufferSizeInKByte); + dml_print("DML::%s: UseUnboundedRequestingFinal = %d\n", __func__, UseUnboundedRequestingFinal); + dml_print("DML::%s: actDETBufferSizeInKByte = %f\n", __func__, actDETBufferSizeInKByte); + dml_print("DML::%s: UnboundedRequestEnabled = %d\n", __func__, *UnboundedRequestEnabled); + dml_print("DML::%s: CompressedBufferSizeInkByte = %d\n", __func__, *CompressedBufferSizeInkByte); +#endif +} + +static bool UnboundedRequest(enum unbounded_requesting_policy UseUnboundedRequestingFinal, int TotalNumberOfActiveDPP, bool NoChroma, enum output_encoder_class Output) +{ + bool ret_val = false; + + ret_val = (UseUnboundedRequestingFinal != dm_unbounded_requesting_disable && TotalNumberOfActiveDPP == 1 && NoChroma); + if (UseUnboundedRequestingFinal == dm_unbounded_requesting_edp_only && Output != dm_edp) { + ret_val = false; + } + return (ret_val); +} + diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.h new file mode 100644 index 000000000000..90be612f26b2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DML31_DISPLAY_MODE_VBA_H__ +#define __DML31_DISPLAY_MODE_VBA_H__ + +void dml31_recalculate(struct display_mode_lib *mode_lib); +void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib); +double dml31_CalculateWriteBackDISPCLK( + enum source_format_class WritebackPixelFormat, + double PixelClock, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackHTaps, + unsigned int WritebackVTaps, + long WritebackSourceWidth, + long WritebackDestinationWidth, + unsigned int HTotal, + unsigned int WritebackLineBufferSize); + +#endif /* __DML31_DISPLAY_MODE_VBA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c new file mode 100644 index 000000000000..3def093ef88e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c @@ -0,0 +1,1724 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "../display_mode_lib.h" +#include "../display_mode_vba.h" +#include "../dml_inline_defs.h" +#include "display_rq_dlg_calc_31.h" + +static bool CalculateBytePerPixelAnd256BBlockSizes( + enum source_format_class SourcePixelFormat, + enum dm_swizzle_mode SurfaceTiling, + unsigned int *BytePerPixelY, + unsigned int *BytePerPixelC, + double *BytePerPixelDETY, + double *BytePerPixelDETC, + unsigned int *BlockHeight256BytesY, + unsigned int *BlockHeight256BytesC, + unsigned int *BlockWidth256BytesY, + unsigned int *BlockWidth256BytesC) +{ + if (SourcePixelFormat == dm_444_64) { + *BytePerPixelDETY = 8; + *BytePerPixelDETC = 0; + *BytePerPixelY = 8; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_32 || SourcePixelFormat == dm_rgbe) { + *BytePerPixelDETY = 4; + *BytePerPixelDETC = 0; + *BytePerPixelY = 4; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_16) { + *BytePerPixelDETY = 2; + *BytePerPixelDETC = 0; + *BytePerPixelY = 2; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_444_8) { + *BytePerPixelDETY = 1; + *BytePerPixelDETC = 0; + *BytePerPixelY = 1; + *BytePerPixelC = 0; + } else if (SourcePixelFormat == dm_rgbe_alpha) { + *BytePerPixelDETY = 4; + *BytePerPixelDETC = 1; + *BytePerPixelY = 4; + *BytePerPixelC = 1; + } else if (SourcePixelFormat == dm_420_8) { + *BytePerPixelDETY = 1; + *BytePerPixelDETC = 2; + *BytePerPixelY = 1; + *BytePerPixelC = 2; + } else if (SourcePixelFormat == dm_420_12) { + *BytePerPixelDETY = 2; + *BytePerPixelDETC = 4; + *BytePerPixelY = 2; + *BytePerPixelC = 4; + } else { + *BytePerPixelDETY = 4.0 / 3; + *BytePerPixelDETC = 8.0 / 3; + *BytePerPixelY = 2; + *BytePerPixelC = 4; + } + + if ((SourcePixelFormat == dm_444_64 || SourcePixelFormat == dm_444_32 || SourcePixelFormat == dm_444_16 || SourcePixelFormat == dm_444_8 || SourcePixelFormat == dm_mono_16 + || SourcePixelFormat == dm_mono_8 || SourcePixelFormat == dm_rgbe)) { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + } else if (SourcePixelFormat == dm_444_64) { + *BlockHeight256BytesY = 4; + } else if (SourcePixelFormat == dm_444_8) { + *BlockHeight256BytesY = 16; + } else { + *BlockHeight256BytesY = 8; + } + *BlockWidth256BytesY = 256U / *BytePerPixelY / *BlockHeight256BytesY; + *BlockHeight256BytesC = 0; + *BlockWidth256BytesC = 0; + } else { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + *BlockHeight256BytesC = 1; + } else if (SourcePixelFormat == dm_rgbe_alpha) { + *BlockHeight256BytesY = 8; + *BlockHeight256BytesC = 16; + } else if (SourcePixelFormat == dm_420_8) { + *BlockHeight256BytesY = 16; + *BlockHeight256BytesC = 8; + } else { + *BlockHeight256BytesY = 8; + *BlockHeight256BytesC = 8; + } + *BlockWidth256BytesY = 256U / *BytePerPixelY / *BlockHeight256BytesY; + *BlockWidth256BytesC = 256U / *BytePerPixelC / *BlockHeight256BytesC; + } + return true; +} + +static bool is_dual_plane(enum source_format_class source_format) +{ + bool ret_val = 0; + + if ((source_format == dm_420_12) || (source_format == dm_420_8) || (source_format == dm_420_10) || (source_format == dm_rgbe_alpha)) + ret_val = 1; + + return ret_val; +} + +static double get_refcyc_per_delivery( + struct display_mode_lib *mode_lib, + double refclk_freq_in_mhz, + double pclk_freq_in_mhz, + unsigned int odm_combine, + unsigned int recout_width, + unsigned int hactive, + double vratio, + double hscale_pixel_rate, + unsigned int delivery_width, + unsigned int req_per_swath_ub) +{ + double refcyc_per_delivery = 0.0; + + if (vratio <= 1.0) { + if (odm_combine) + refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) ((unsigned int) odm_combine * 2) + * dml_min((double) recout_width, (double) hactive / ((unsigned int) odm_combine * 2)) / pclk_freq_in_mhz / (double) req_per_swath_ub; + else + refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) recout_width / pclk_freq_in_mhz / (double) req_per_swath_ub; + } else { + refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) delivery_width / (double) hscale_pixel_rate / (double) req_per_swath_ub; + } + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); + dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); + dml_print("DML_DLG: %s: recout_width = %d\n", __func__, recout_width); + dml_print("DML_DLG: %s: vratio = %3.2f\n", __func__, vratio); + dml_print("DML_DLG: %s: req_per_swath_ub = %d\n", __func__, req_per_swath_ub); + dml_print("DML_DLG: %s: hscale_pixel_rate = %3.2f\n", __func__, hscale_pixel_rate); + dml_print("DML_DLG: %s: delivery_width = %d\n", __func__, delivery_width); + dml_print("DML_DLG: %s: refcyc_per_delivery= %3.2f\n", __func__, refcyc_per_delivery); +#endif + + return refcyc_per_delivery; + +} + +static unsigned int get_blk_size_bytes(const enum source_macro_tile_size tile_size) +{ + if (tile_size == dm_256k_tile) + return (256 * 1024); + else if (tile_size == dm_64k_tile) + return (64 * 1024); + else + return (4 * 1024); +} + +static void extract_rq_sizing_regs(struct display_mode_lib *mode_lib, display_data_rq_regs_st *rq_regs, const display_data_rq_sizing_params_st rq_sizing) +{ + print__data_rq_sizing_params_st(mode_lib, rq_sizing); + + rq_regs->chunk_size = dml_log2(rq_sizing.chunk_bytes) - 10; + + if (rq_sizing.min_chunk_bytes == 0) + rq_regs->min_chunk_size = 0; + else + rq_regs->min_chunk_size = dml_log2(rq_sizing.min_chunk_bytes) - 8 + 1; + + rq_regs->meta_chunk_size = dml_log2(rq_sizing.meta_chunk_bytes) - 10; + if (rq_sizing.min_meta_chunk_bytes == 0) + rq_regs->min_meta_chunk_size = 0; + else + rq_regs->min_meta_chunk_size = dml_log2(rq_sizing.min_meta_chunk_bytes) - 6 + 1; + + rq_regs->dpte_group_size = dml_log2(rq_sizing.dpte_group_bytes) - 6; + rq_regs->mpte_group_size = dml_log2(rq_sizing.mpte_group_bytes) - 6; +} + +static void extract_rq_regs(struct display_mode_lib *mode_lib, display_rq_regs_st *rq_regs, const display_rq_params_st rq_param) +{ + unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; + unsigned int detile_buf_plane1_addr = 0; + + extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_l), rq_param.sizing.rq_l); + + rq_regs->rq_regs_l.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_l.dpte_row_height), 1) - 3; + + if (rq_param.yuv420) { + extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_c), rq_param.sizing.rq_c); + rq_regs->rq_regs_c.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_c.dpte_row_height), 1) - 3; + } + + rq_regs->rq_regs_l.swath_height = dml_log2(rq_param.dlg.rq_l.swath_height); + rq_regs->rq_regs_c.swath_height = dml_log2(rq_param.dlg.rq_c.swath_height); + + // FIXME: take the max between luma, chroma chunk size? + // okay for now, as we are setting chunk_bytes to 8kb anyways + if (rq_param.sizing.rq_l.chunk_bytes >= 32 * 1024 || (rq_param.yuv420 && rq_param.sizing.rq_c.chunk_bytes >= 32 * 1024)) { //32kb + rq_regs->drq_expansion_mode = 0; + } else { + rq_regs->drq_expansion_mode = 2; + } + rq_regs->prq_expansion_mode = 1; + rq_regs->mrq_expansion_mode = 1; + rq_regs->crq_expansion_mode = 1; + + // Note: detile_buf_plane1_addr is in unit of 1KB + if (rq_param.yuv420) { + if ((double) rq_param.misc.rq_l.stored_swath_bytes / (double) rq_param.misc.rq_c.stored_swath_bytes <= 1.5) { + detile_buf_plane1_addr = (detile_buf_size_in_bytes / 2.0 / 1024.0); // half to chroma +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: detile_buf_plane1_addr = %0d (1/2 to chroma)\n", __func__, detile_buf_plane1_addr); +#endif + } else { + detile_buf_plane1_addr = dml_round_to_multiple((unsigned int) ((2.0 * detile_buf_size_in_bytes) / 3.0), 1024, 0) / 1024.0; // 2/3 to luma +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: detile_buf_plane1_addr = %0d (1/3 chroma)\n", __func__, detile_buf_plane1_addr); +#endif + } + } + rq_regs->plane1_base_address = detile_buf_plane1_addr; + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: detile_buf_size_in_bytes = %0d\n", __func__, detile_buf_size_in_bytes); + dml_print("DML_DLG: %s: detile_buf_plane1_addr = %0d\n", __func__, detile_buf_plane1_addr); + dml_print("DML_DLG: %s: plane1_base_address = %0d\n", __func__, rq_regs->plane1_base_address); + dml_print("DML_DLG: %s: rq_l.stored_swath_bytes = %0d\n", __func__, rq_param.misc.rq_l.stored_swath_bytes); + dml_print("DML_DLG: %s: rq_c.stored_swath_bytes = %0d\n", __func__, rq_param.misc.rq_c.stored_swath_bytes); + dml_print("DML_DLG: %s: rq_l.swath_height = %0d\n", __func__, rq_param.dlg.rq_l.swath_height); + dml_print("DML_DLG: %s: rq_c.swath_height = %0d\n", __func__, rq_param.dlg.rq_c.swath_height); +#endif +} + +static void handle_det_buf_split(struct display_mode_lib *mode_lib, display_rq_params_st *rq_param, const display_pipe_source_params_st pipe_src_param) +{ + unsigned int total_swath_bytes = 0; + unsigned int swath_bytes_l = 0; + unsigned int swath_bytes_c = 0; + unsigned int full_swath_bytes_packed_l = 0; + unsigned int full_swath_bytes_packed_c = 0; + bool req128_l = 0; + bool req128_c = 0; + bool surf_linear = (pipe_src_param.sw_mode == dm_sw_linear); + bool surf_vert = (pipe_src_param.source_scan == dm_vert); + unsigned int log2_swath_height_l = 0; + unsigned int log2_swath_height_c = 0; + unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; + + full_swath_bytes_packed_l = rq_param->misc.rq_l.full_swath_bytes; + full_swath_bytes_packed_c = rq_param->misc.rq_c.full_swath_bytes; + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: full_swath_bytes_packed_l = %0d\n", __func__, full_swath_bytes_packed_l); + dml_print("DML_DLG: %s: full_swath_bytes_packed_c = %0d\n", __func__, full_swath_bytes_packed_c); +#endif + + if (rq_param->yuv420_10bpc) { + full_swath_bytes_packed_l = dml_round_to_multiple(rq_param->misc.rq_l.full_swath_bytes * 2.0 / 3.0, 256, 1) + 256; + full_swath_bytes_packed_c = dml_round_to_multiple(rq_param->misc.rq_c.full_swath_bytes * 2.0 / 3.0, 256, 1) + 256; +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: full_swath_bytes_packed_l = %0d (3-2 packing)\n", __func__, full_swath_bytes_packed_l); + dml_print("DML_DLG: %s: full_swath_bytes_packed_c = %0d (3-2 packing)\n", __func__, full_swath_bytes_packed_c); +#endif + } + + if (rq_param->yuv420) + total_swath_bytes = 2 * full_swath_bytes_packed_l + 2 * full_swath_bytes_packed_c; + else + total_swath_bytes = 2 * full_swath_bytes_packed_l; + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: total_swath_bytes = %0d\n", __func__, total_swath_bytes); + dml_print("DML_DLG: %s: detile_buf_size_in_bytes = %0d\n", __func__, detile_buf_size_in_bytes); +#endif + + if (total_swath_bytes <= detile_buf_size_in_bytes) { //full 256b request + req128_l = 0; + req128_c = 0; + swath_bytes_l = full_swath_bytes_packed_l; + swath_bytes_c = full_swath_bytes_packed_c; + } else if (!rq_param->yuv420) { + req128_l = 1; + req128_c = 0; + swath_bytes_c = full_swath_bytes_packed_c; + swath_bytes_l = full_swath_bytes_packed_l / 2; + } else if ((double) full_swath_bytes_packed_l / (double) full_swath_bytes_packed_c < 1.5) { + req128_l = 0; + req128_c = 1; + swath_bytes_l = full_swath_bytes_packed_l; + swath_bytes_c = full_swath_bytes_packed_c / 2; + + total_swath_bytes = 2 * swath_bytes_l + 2 * swath_bytes_c; + + if (total_swath_bytes > detile_buf_size_in_bytes) { + req128_l = 1; + swath_bytes_l = full_swath_bytes_packed_l / 2; + } + } else { + req128_l = 1; + req128_c = 0; + swath_bytes_l = full_swath_bytes_packed_l / 2; + swath_bytes_c = full_swath_bytes_packed_c; + + total_swath_bytes = 2 * swath_bytes_l + 2 * swath_bytes_c; + + if (total_swath_bytes > detile_buf_size_in_bytes) { + req128_c = 1; + swath_bytes_c = full_swath_bytes_packed_c / 2; + } + } + + if (rq_param->yuv420) + total_swath_bytes = 2 * swath_bytes_l + 2 * swath_bytes_c; + else + total_swath_bytes = 2 * swath_bytes_l; + + rq_param->misc.rq_l.stored_swath_bytes = swath_bytes_l; + rq_param->misc.rq_c.stored_swath_bytes = swath_bytes_c; + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: total_swath_bytes = %0d\n", __func__, total_swath_bytes); + dml_print("DML_DLG: %s: rq_l.stored_swath_bytes = %0d\n", __func__, rq_param->misc.rq_l.stored_swath_bytes); + dml_print("DML_DLG: %s: rq_c.stored_swath_bytes = %0d\n", __func__, rq_param->misc.rq_c.stored_swath_bytes); +#endif + if (surf_linear) { + log2_swath_height_l = 0; + log2_swath_height_c = 0; + } else { + unsigned int swath_height_l; + unsigned int swath_height_c; + + if (!surf_vert) { + swath_height_l = rq_param->misc.rq_l.blk256_height; + swath_height_c = rq_param->misc.rq_c.blk256_height; + } else { + swath_height_l = rq_param->misc.rq_l.blk256_width; + swath_height_c = rq_param->misc.rq_c.blk256_width; + } + + if (swath_height_l > 0) + log2_swath_height_l = dml_log2(swath_height_l); + + if (req128_l && log2_swath_height_l > 0) + log2_swath_height_l -= 1; + + if (swath_height_c > 0) + log2_swath_height_c = dml_log2(swath_height_c); + + if (req128_c && log2_swath_height_c > 0) + log2_swath_height_c -= 1; + } + + rq_param->dlg.rq_l.swath_height = 1 << log2_swath_height_l; + rq_param->dlg.rq_c.swath_height = 1 << log2_swath_height_c; + +#ifdef __DML_RQ_DLG_CALC_DEBUG__ + dml_print("DML_DLG: %s: req128_l = %0d\n", __func__, req128_l); + dml_print("DML_DLG: %s: req128_c = %0d\n", __func__, req128_c); + dml_print("DML_DLG: %s: full_swath_bytes_packed_l = %0d\n", __func__, full_swath_bytes_packed_l); + dml_print("DML_DLG: %s: full_swath_bytes_packed_c = %0d\n", __func__, full_swath_bytes_packed_c); + dml_print("DML_DLG: %s: swath_height luma = %0d\n", __func__, rq_param->dlg.rq_l.swath_height); + dml_print("DML_DLG: %s: swath_height chroma = %0d\n", __func__, rq_param->dlg.rq_c.swath_height); +#endif +} + +static void get_meta_and_pte_attr( + struct display_mode_lib *mode_lib, + display_data_rq_dlg_params_st *rq_dlg_param, + display_data_rq_misc_params_st *rq_misc_param, + display_data_rq_sizing_params_st *rq_sizing_param, + unsigned int vp_width, + unsigned int vp_height, + unsigned int data_pitch, + unsigned int meta_pitch, + unsigned int source_format, + unsigned int tiling, + unsigned int macro_tile_size, + unsigned int source_scan, + unsigned int hostvm_enable, + unsigned int is_chroma, + unsigned int surface_height) +{ + bool surf_linear = (tiling == dm_sw_linear); + bool surf_vert = (source_scan == dm_vert); + + unsigned int bytes_per_element; + unsigned int bytes_per_element_y; + unsigned int bytes_per_element_c; + + unsigned int blk256_width = 0; + unsigned int blk256_height = 0; + + unsigned int blk256_width_y = 0; + unsigned int blk256_height_y = 0; + unsigned int blk256_width_c = 0; + unsigned int blk256_height_c = 0; + unsigned int log2_bytes_per_element; + unsigned int log2_blk256_width; + unsigned int log2_blk256_height; + unsigned int blk_bytes; + unsigned int log2_blk_bytes; + unsigned int log2_blk_height; + unsigned int log2_blk_width; + unsigned int log2_meta_req_bytes; + unsigned int log2_meta_req_height; + unsigned int log2_meta_req_width; + unsigned int meta_req_width; + unsigned int meta_req_height; + unsigned int log2_meta_row_height; + unsigned int meta_row_width_ub; + unsigned int log2_meta_chunk_bytes; + unsigned int log2_meta_chunk_height; + + //full sized meta chunk width in unit of data elements + unsigned int log2_meta_chunk_width; + unsigned int log2_min_meta_chunk_bytes; + unsigned int min_meta_chunk_width; + unsigned int meta_chunk_width; + unsigned int meta_chunk_per_row_int; + unsigned int meta_row_remainder; + unsigned int meta_chunk_threshold; + unsigned int meta_blk_height; + unsigned int meta_surface_bytes; + unsigned int vmpg_bytes; + unsigned int meta_pte_req_per_frame_ub; + unsigned int meta_pte_bytes_per_frame_ub; + const unsigned int log2_vmpg_bytes = dml_log2(mode_lib->soc.gpuvm_min_page_size_bytes); + const bool dual_plane_en = is_dual_plane((enum source_format_class) (source_format)); + const unsigned int dpte_buf_in_pte_reqs = + dual_plane_en ? (is_chroma ? mode_lib->ip.dpte_buffer_size_in_pte_reqs_chroma : mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma) : (mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma + + mode_lib->ip.dpte_buffer_size_in_pte_reqs_chroma); + + unsigned int log2_vmpg_height = 0; + unsigned int log2_vmpg_width = 0; + unsigned int log2_dpte_req_height_ptes = 0; + unsigned int log2_dpte_req_height = 0; + unsigned int log2_dpte_req_width = 0; + unsigned int log2_dpte_row_height_linear = 0; + unsigned int log2_dpte_row_height = 0; + unsigned int log2_dpte_group_width = 0; + unsigned int dpte_row_width_ub = 0; + unsigned int dpte_req_height = 0; + unsigned int dpte_req_width = 0; + unsigned int dpte_group_width = 0; + unsigned int log2_dpte_group_bytes = 0; + unsigned int log2_dpte_group_length = 0; + double byte_per_pixel_det_y; + double byte_per_pixel_det_c; + + CalculateBytePerPixelAnd256BBlockSizes( + (enum source_format_class) (source_format), + (enum dm_swizzle_mode) (tiling), + &bytes_per_element_y, + &bytes_per_element_c, + &byte_per_pixel_det_y, + &byte_per_pixel_det_c, + &blk256_height_y, + &blk256_height_c, + &blk256_width_y, + &blk256_width_c); + + if (!is_chroma) { + blk256_width = blk256_width_y; + blk256_height = blk256_height_y; + bytes_per_element = bytes_per_element_y; + } else { + blk256_width = blk256_width_c; + blk256_height = blk256_height_c; + bytes_per_element = bytes_per_element_c; + } + + log2_bytes_per_element = dml_log2(bytes_per_element); + + dml_print("DML_DLG: %s: surf_linear = %d\n", __func__, surf_linear); + dml_print("DML_DLG: %s: surf_vert = %d\n", __func__, surf_vert); + dml_print("DML_DLG: %s: blk256_width = %d\n", __func__, blk256_width); + dml_print("DML_DLG: %s: blk256_height = %d\n", __func__, blk256_height); + + log2_blk256_width = dml_log2((double) blk256_width); + log2_blk256_height = dml_log2((double) blk256_height); + blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); + log2_blk_bytes = dml_log2((double) blk_bytes); + log2_blk_height = 0; + log2_blk_width = 0; + + // remember log rule + // "+" in log is multiply + // "-" in log is divide + // "/2" is like square root + // blk is vertical biased + if (tiling != dm_sw_linear) + log2_blk_height = log2_blk256_height + dml_ceil((double) (log2_blk_bytes - 8) / 2.0, 1); + else + log2_blk_height = 0; // blk height of 1 + + log2_blk_width = log2_blk_bytes - log2_bytes_per_element - log2_blk_height; + + if (!surf_vert) { + int unsigned temp; + + temp = dml_round_to_multiple(vp_width - 1, blk256_width, 1) + blk256_width; + if (data_pitch < blk256_width) { + dml_print("WARNING: DML_DLG: %s: swath_size calculation ignoring data_pitch=%u < blk256_width=%u\n", __func__, data_pitch, blk256_width); + } else { + if (temp > data_pitch) { + if (data_pitch >= vp_width) + temp = data_pitch; + else + dml_print("WARNING: DML_DLG: %s: swath_size calculation ignoring data_pitch=%u < vp_width=%u\n", __func__, data_pitch, vp_width); + } + } + rq_dlg_param->swath_width_ub = temp; + rq_dlg_param->req_per_swath_ub = temp >> log2_blk256_width; + } else { + int unsigned temp; + + temp = dml_round_to_multiple(vp_height - 1, blk256_height, 1) + blk256_height; + if (surface_height < blk256_height) { + dml_print("WARNING: DML_DLG: %s swath_size calculation ignored surface_height=%u < blk256_height=%u\n", __func__, surface_height, blk256_height); + } else { + if (temp > surface_height) { + if (surface_height >= vp_height) + temp = surface_height; + else + dml_print("WARNING: DML_DLG: %s swath_size calculation ignored surface_height=%u < vp_height=%u\n", __func__, surface_height, vp_height); + } + } + rq_dlg_param->swath_width_ub = temp; + rq_dlg_param->req_per_swath_ub = temp >> log2_blk256_height; + } + + if (!surf_vert) + rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_height * bytes_per_element; + else + rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_width * bytes_per_element; + + rq_misc_param->blk256_height = blk256_height; + rq_misc_param->blk256_width = blk256_width; + + // ------- + // meta + // ------- + log2_meta_req_bytes = 6; // meta request is 64b and is 8x8byte meta element + + // each 64b meta request for dcn is 8x8 meta elements and + // a meta element covers one 256b block of the the data surface. + log2_meta_req_height = log2_blk256_height + 3; // meta req is 8x8 byte, each byte represent 1 blk256 + log2_meta_req_width = log2_meta_req_bytes + 8 - log2_bytes_per_element - log2_meta_req_height; + meta_req_width = 1 << log2_meta_req_width; + meta_req_height = 1 << log2_meta_req_height; + log2_meta_row_height = 0; + meta_row_width_ub = 0; + + // the dimensions of a meta row are meta_row_width x meta_row_height in elements. + // calculate upper bound of the meta_row_width + if (!surf_vert) { + log2_meta_row_height = log2_meta_req_height; + meta_row_width_ub = dml_round_to_multiple(vp_width - 1, meta_req_width, 1) + meta_req_width; + rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_width; + } else { + log2_meta_row_height = log2_meta_req_width; + meta_row_width_ub = dml_round_to_multiple(vp_height - 1, meta_req_height, 1) + meta_req_height; + rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_height; + } + rq_dlg_param->meta_bytes_per_row_ub = rq_dlg_param->meta_req_per_row_ub * 64; + + rq_dlg_param->meta_row_height = 1 << log2_meta_row_height; + + log2_meta_chunk_bytes = dml_log2(rq_sizing_param->meta_chunk_bytes); + log2_meta_chunk_height = log2_meta_row_height; + + //full sized meta chunk width in unit of data elements + log2_meta_chunk_width = log2_meta_chunk_bytes + 8 - log2_bytes_per_element - log2_meta_chunk_height; + log2_min_meta_chunk_bytes = dml_log2(rq_sizing_param->min_meta_chunk_bytes); + min_meta_chunk_width = 1 << (log2_min_meta_chunk_bytes + 8 - log2_bytes_per_element - log2_meta_chunk_height); + meta_chunk_width = 1 << log2_meta_chunk_width; + meta_chunk_per_row_int = (unsigned int) (meta_row_width_ub / meta_chunk_width); + meta_row_remainder = meta_row_width_ub % meta_chunk_width; + meta_chunk_threshold = 0; + meta_blk_height = blk256_height * 64; + meta_surface_bytes = meta_pitch * (dml_round_to_multiple(vp_height - 1, meta_blk_height, 1) + meta_blk_height) * bytes_per_element / 256; + vmpg_bytes = mode_lib->soc.gpuvm_min_page_size_bytes; + meta_pte_req_per_frame_ub = (dml_round_to_multiple(meta_surface_bytes - vmpg_bytes, 8 * vmpg_bytes, 1) + 8 * vmpg_bytes) / (8 * vmpg_bytes); + meta_pte_bytes_per_frame_ub = meta_pte_req_per_frame_ub * 64; //64B mpte request + rq_dlg_param->meta_pte_bytes_per_frame_ub = meta_pte_bytes_per_frame_ub; + + dml_print("DML_DLG: %s: meta_blk_height = %d\n", __func__, meta_blk_height); + dml_print("DML_DLG: %s: meta_surface_bytes = %d\n", __func__, meta_surface_bytes); + dml_print("DML_DLG: %s: meta_pte_req_per_frame_ub = %d\n", __func__, meta_pte_req_per_frame_ub); + dml_print("DML_DLG: %s: meta_pte_bytes_per_frame_ub = %d\n", __func__, meta_pte_bytes_per_frame_ub); + + if (!surf_vert) + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_width; + else + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_height; + + if (meta_row_remainder <= meta_chunk_threshold) + rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 1; + else + rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 2; + + // ------ + // dpte + // ------ + if (surf_linear) { + log2_vmpg_height = 0; // one line high + } else { + log2_vmpg_height = (log2_vmpg_bytes - 8) / 2 + log2_blk256_height; + } + log2_vmpg_width = log2_vmpg_bytes - log2_bytes_per_element - log2_vmpg_height; + + // only 3 possible shapes for dpte request in dimensions of ptes: 8x1, 4x2, 2x4. + if (surf_linear) { //one 64B PTE request returns 8 PTEs + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_vmpg_width + 3; + log2_dpte_req_height = 0; + } else if (log2_blk_bytes == 12) { //4KB tile means 4kB page size + //one 64B req gives 8x1 PTEs for 4KB tile + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_blk_width + 3; + log2_dpte_req_height = log2_blk_height + 0; + } else if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) { // tile block >= 64KB + //two 64B reqs of 2x4 PTEs give 16 PTEs to cover 64KB + log2_dpte_req_height_ptes = 4; + log2_dpte_req_width = log2_blk256_width + 4; // log2_64KB_width + log2_dpte_req_height = log2_blk256_height + 4; // log2_64KB_height + } else { //64KB page size and must 64KB tile block + //one 64B req gives 8x1 PTEs for 64KB tile + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_blk_width + 3; + log2_dpte_req_height = log2_blk_height + 0; + } + + // The dpte request dimensions in data elements is dpte_req_width x dpte_req_height + // log2_vmpg_width is how much 1 pte represent, now calculating how much a 64b pte req represent + // That depends on the pte shape (i.e. 8x1, 4x2, 2x4) + //log2_dpte_req_height = log2_vmpg_height + log2_dpte_req_height_ptes; + //log2_dpte_req_width = log2_vmpg_width + log2_dpte_req_width_ptes; + dpte_req_height = 1 << log2_dpte_req_height; + dpte_req_width = 1 << log2_dpte_req_width; + + // calculate pitch dpte row buffer can hold + // round the result down to a power of two. + if (surf_linear) { + unsigned int dpte_row_height; + + log2_dpte_row_height_linear = dml_floor(dml_log2(dpte_buf_in_pte_reqs * dpte_req_width / data_pitch), 1); + + dml_print("DML_DLG: %s: is_chroma = %d\n", __func__, is_chroma); + dml_print("DML_DLG: %s: dpte_buf_in_pte_reqs = %d\n", __func__, dpte_buf_in_pte_reqs); + dml_print("DML_DLG: %s: log2_dpte_row_height_linear = %d\n", __func__, log2_dpte_row_height_linear); + + ASSERT(log2_dpte_row_height_linear >= 3); + + if (log2_dpte_row_height_linear > 7) + log2_dpte_row_height_linear = 7; + + log2_dpte_row_height = log2_dpte_row_height_linear; + // For linear, the dpte row is pitch dependent and the pte requests wrap at the pitch boundary. + // the dpte_row_width_ub is the upper bound of data_pitch*dpte_row_height in elements with this unique buffering. + dpte_row_height = 1 << log2_dpte_row_height; + dpte_row_width_ub = dml_round_to_multiple(data_pitch * dpte_row_height - 1, dpte_req_width, 1) + dpte_req_width; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; + } else { + // the upper bound of the dpte_row_width without dependency on viewport position follows. + // for tiled mode, row height is the same as req height and row store up to vp size upper bound + if (!surf_vert) { + log2_dpte_row_height = log2_dpte_req_height; + dpte_row_width_ub = dml_round_to_multiple(vp_width - 1, dpte_req_width, 1) + dpte_req_width; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; + } else { + log2_dpte_row_height = (log2_blk_width < log2_dpte_req_width) ? log2_blk_width : log2_dpte_req_width; + dpte_row_width_ub = dml_round_to_multiple(vp_height - 1, dpte_req_height, 1) + dpte_req_height; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_height; + } + } + if (log2_blk_bytes >= 16 && log2_vmpg_bytes == 12) // tile block >= 64KB + rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 128; //2*64B dpte request + else + rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 64; //64B dpte request + + rq_dlg_param->dpte_row_height = 1 << log2_dpte_row_height; + + // the dpte_group_bytes is reduced for the specific case of vertical + // access of a tile surface that has dpte request of 8x1 ptes. + if (hostvm_enable) + rq_sizing_param->dpte_group_bytes = 512; + else { + if (!surf_linear & (log2_dpte_req_height_ptes == 0) & surf_vert) //reduced, in this case, will have page fault within a group + rq_sizing_param->dpte_group_bytes = 512; + else + rq_sizing_param->dpte_group_bytes = 2048; + } + + //since pte request size is 64byte, the number of data pte requests per full sized group is as follows. + log2_dpte_group_bytes = dml_log2(rq_sizing_param->dpte_group_bytes); + log2_dpte_group_length = log2_dpte_group_bytes - 6; //length in 64b requests + + // full sized data pte group width in elements + if (!surf_vert) + log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_width; + else + log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_height; + + //But if the tile block >=64KB and the page size is 4KB, then each dPTE request is 2*64B + if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) // tile block >= 64KB + log2_dpte_group_width = log2_dpte_group_width - 1; + + dpte_group_width = 1 << log2_dpte_group_width; + + // since dpte groups are only aligned to dpte_req_width and not dpte_group_width, + // the upper bound for the dpte groups per row is as follows. + rq_dlg_param->dpte_groups_per_row_ub = dml_ceil((double) dpte_row_width_ub / dpte_group_width, 1); +} + +static void get_surf_rq_param( + struct display_mode_lib *mode_lib, + display_data_rq_sizing_params_st *rq_sizing_param, + display_data_rq_dlg_params_st *rq_dlg_param, + display_data_rq_misc_params_st *rq_misc_param, + const display_pipe_params_st pipe_param, + bool is_chroma, + bool is_alpha) +{ + bool mode_422 = 0; + unsigned int vp_width = 0; + unsigned int vp_height = 0; + unsigned int data_pitch = 0; + unsigned int meta_pitch = 0; + unsigned int surface_height = 0; + unsigned int ppe = mode_422 ? 2 : 1; + + // FIXME check if ppe apply for both luma and chroma in 422 case + if (is_chroma | is_alpha) { + vp_width = pipe_param.src.viewport_width_c / ppe; + vp_height = pipe_param.src.viewport_height_c; + data_pitch = pipe_param.src.data_pitch_c; + meta_pitch = pipe_param.src.meta_pitch_c; + surface_height = pipe_param.src.surface_height_y / 2.0; + } else { + vp_width = pipe_param.src.viewport_width / ppe; + vp_height = pipe_param.src.viewport_height; + data_pitch = pipe_param.src.data_pitch; + meta_pitch = pipe_param.src.meta_pitch; + surface_height = pipe_param.src.surface_height_y; + } + + if (pipe_param.dest.odm_combine) { + unsigned int access_dir; + unsigned int full_src_vp_width; + unsigned int hactive_odm; + unsigned int src_hactive_odm; + + access_dir = (pipe_param.src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed + hactive_odm = pipe_param.dest.hactive / ((unsigned int) pipe_param.dest.odm_combine * 2); + if (is_chroma) { + full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio_c * pipe_param.dest.full_recout_width; + src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio_c * hactive_odm; + } else { + full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio * pipe_param.dest.full_recout_width; + src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio * hactive_odm; + } + + if (access_dir == 0) { + vp_width = dml_min(full_src_vp_width, src_hactive_odm); + dml_print("DML_DLG: %s: vp_width = %d\n", __func__, vp_width); + } else { + vp_height = dml_min(full_src_vp_width, src_hactive_odm); + dml_print("DML_DLG: %s: vp_height = %d\n", __func__, vp_height); + + } + dml_print("DML_DLG: %s: full_src_vp_width = %d\n", __func__, full_src_vp_width); + dml_print("DML_DLG: %s: hactive_odm = %d\n", __func__, hactive_odm); + dml_print("DML_DLG: %s: src_hactive_odm = %d\n", __func__, src_hactive_odm); + } + + rq_sizing_param->chunk_bytes = 8192; + + if (is_alpha) { + rq_sizing_param->chunk_bytes = 4096; + } + + if (rq_sizing_param->chunk_bytes == 64 * 1024) + rq_sizing_param->min_chunk_bytes = 0; + else + rq_sizing_param->min_chunk_bytes = 1024; + + rq_sizing_param->meta_chunk_bytes = 2048; + rq_sizing_param->min_meta_chunk_bytes = 256; + + if (pipe_param.src.hostvm) + rq_sizing_param->mpte_group_bytes = 512; + else + rq_sizing_param->mpte_group_bytes = 2048; + + get_meta_and_pte_attr( + mode_lib, + rq_dlg_param, + rq_misc_param, + rq_sizing_param, + vp_width, + vp_height, + data_pitch, + meta_pitch, + pipe_param.src.source_format, + pipe_param.src.sw_mode, + pipe_param.src.macro_tile_size, + pipe_param.src.source_scan, + pipe_param.src.hostvm, + is_chroma, + surface_height); +} + +static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib, display_rq_params_st *rq_param, const display_pipe_params_st pipe_param) +{ + // get param for luma surface + rq_param->yuv420 = pipe_param.src.source_format == dm_420_8 || pipe_param.src.source_format == dm_420_10 || pipe_param.src.source_format == dm_rgbe_alpha + || pipe_param.src.source_format == dm_420_12; + + rq_param->yuv420_10bpc = pipe_param.src.source_format == dm_420_10; + + rq_param->rgbe_alpha = (pipe_param.src.source_format == dm_rgbe_alpha) ? 1 : 0; + + get_surf_rq_param(mode_lib, &(rq_param->sizing.rq_l), &(rq_param->dlg.rq_l), &(rq_param->misc.rq_l), pipe_param, 0, 0); + + if (is_dual_plane((enum source_format_class) (pipe_param.src.source_format))) { + // get param for chroma surface + get_surf_rq_param(mode_lib, &(rq_param->sizing.rq_c), &(rq_param->dlg.rq_c), &(rq_param->misc.rq_c), pipe_param, 1, rq_param->rgbe_alpha); + } + + // calculate how to split the det buffer space between luma and chroma + handle_det_buf_split(mode_lib, rq_param, pipe_param.src); + print__rq_params_st(mode_lib, *rq_param); +} + +void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, display_rq_regs_st *rq_regs, const display_pipe_params_st pipe_param) +{ + display_rq_params_st rq_param = {0}; + + memset(rq_regs, 0, sizeof(*rq_regs)); + dml_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param); + extract_rq_regs(mode_lib, rq_regs, rq_param); + + print__rq_regs_st(mode_lib, *rq_regs); +} + +static void calculate_ttu_cursor( + struct display_mode_lib *mode_lib, + double *refcyc_per_req_delivery_pre_cur, + double *refcyc_per_req_delivery_cur, + double refclk_freq_in_mhz, + double ref_freq_to_pix_freq, + double hscale_pixel_rate_l, + double hscl_ratio, + double vratio_pre_l, + double vratio_l, + unsigned int cur_width, + enum cursor_bpp cur_bpp) +{ + unsigned int cur_src_width = cur_width; + unsigned int cur_req_size = 0; + unsigned int cur_req_width = 0; + double cur_width_ub = 0.0; + double cur_req_per_width = 0.0; + double hactive_cur = 0.0; + + ASSERT(cur_src_width <= 256); + + *refcyc_per_req_delivery_pre_cur = 0.0; + *refcyc_per_req_delivery_cur = 0.0; + if (cur_src_width > 0) { + unsigned int cur_bit_per_pixel = 0; + + if (cur_bpp == dm_cur_2bit) { + cur_req_size = 64; // byte + cur_bit_per_pixel = 2; + } else { // 32bit + cur_bit_per_pixel = 32; + if (cur_src_width >= 1 && cur_src_width <= 16) + cur_req_size = 64; + else if (cur_src_width >= 17 && cur_src_width <= 31) + cur_req_size = 128; + else + cur_req_size = 256; + } + + cur_req_width = (double) cur_req_size / ((double) cur_bit_per_pixel / 8.0); + cur_width_ub = dml_ceil((double) cur_src_width / (double) cur_req_width, 1) * (double) cur_req_width; + cur_req_per_width = cur_width_ub / (double) cur_req_width; + hactive_cur = (double) cur_src_width / hscl_ratio; // FIXME: oswin to think about what to do for cursor + + if (vratio_pre_l <= 1.0) { + *refcyc_per_req_delivery_pre_cur = hactive_cur * ref_freq_to_pix_freq / (double) cur_req_per_width; + } else { + *refcyc_per_req_delivery_pre_cur = (double) refclk_freq_in_mhz * (double) cur_src_width / hscale_pixel_rate_l / (double) cur_req_per_width; + } + + ASSERT(*refcyc_per_req_delivery_pre_cur < dml_pow(2, 13)); + + if (vratio_l <= 1.0) { + *refcyc_per_req_delivery_cur = hactive_cur * ref_freq_to_pix_freq / (double) cur_req_per_width; + } else { + *refcyc_per_req_delivery_cur = (double) refclk_freq_in_mhz * (double) cur_src_width / hscale_pixel_rate_l / (double) cur_req_per_width; + } + + dml_print("DML_DLG: %s: cur_req_width = %d\n", __func__, cur_req_width); + dml_print("DML_DLG: %s: cur_width_ub = %3.2f\n", __func__, cur_width_ub); + dml_print("DML_DLG: %s: cur_req_per_width = %3.2f\n", __func__, cur_req_per_width); + dml_print("DML_DLG: %s: hactive_cur = %3.2f\n", __func__, hactive_cur); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_cur = %3.2f\n", __func__, *refcyc_per_req_delivery_pre_cur); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_cur = %3.2f\n", __func__, *refcyc_per_req_delivery_cur); + + ASSERT(*refcyc_per_req_delivery_cur < dml_pow(2, 13)); + } +} + +// Note: currently taken in as is. +// Nice to decouple code from hw register implement and extract code that are repeated for luma and chroma. +static void dml_rq_dlg_get_dlg_params( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + display_dlg_regs_st *disp_dlg_regs, + display_ttu_regs_st *disp_ttu_regs, + const display_rq_dlg_params_st rq_dlg_param, + const display_dlg_sys_params_st dlg_sys_param, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support) +{ + const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; + const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; + const display_output_params_st *dout = &e2e_pipe_param[pipe_idx].dout; + const display_clocks_and_cfg_st *clks = &e2e_pipe_param[pipe_idx].clks_cfg; + const scaler_ratio_depth_st *scl = &e2e_pipe_param[pipe_idx].pipe.scale_ratio_depth; + const scaler_taps_st *taps = &e2e_pipe_param[pipe_idx].pipe.scale_taps; + unsigned int pipe_index_in_combine[DC__NUM_PIPES__MAX]; + + // ------------------------- + // Section 1.15.2.1: OTG dependent Params + // ------------------------- + // Timing + unsigned int htotal = dst->htotal; + unsigned int hblank_end = dst->hblank_end; + unsigned int vblank_start = dst->vblank_start; + unsigned int vblank_end = dst->vblank_end; + + double dppclk_freq_in_mhz = clks->dppclk_mhz; + double refclk_freq_in_mhz = clks->refclk_mhz; + double pclk_freq_in_mhz = dst->pixel_rate_mhz; + bool interlaced = dst->interlaced; + double ref_freq_to_pix_freq = refclk_freq_in_mhz / pclk_freq_in_mhz; + double min_ttu_vblank; + unsigned int dlg_vblank_start; + bool dual_plane; + bool mode_422; + unsigned int access_dir; + unsigned int vp_height_l; + unsigned int vp_width_l; + unsigned int vp_height_c; + unsigned int vp_width_c; + + // Scaling + unsigned int htaps_l; + unsigned int htaps_c; + double hratio_l; + double hratio_c; + double vratio_l; + double vratio_c; + bool scl_enable; + + unsigned int swath_width_ub_l; + unsigned int dpte_groups_per_row_ub_l; + unsigned int swath_width_ub_c; + unsigned int dpte_groups_per_row_ub_c; + + unsigned int meta_chunks_per_row_ub_l; + unsigned int meta_chunks_per_row_ub_c; + unsigned int vupdate_offset; + unsigned int vupdate_width; + unsigned int vready_offset; + + unsigned int dppclk_delay_subtotal; + unsigned int dispclk_delay_subtotal; + + unsigned int vstartup_start; + unsigned int dst_x_after_scaler; + unsigned int dst_y_after_scaler; + double dst_y_prefetch; + double dst_y_per_vm_vblank; + double dst_y_per_row_vblank; + double dst_y_per_vm_flip; + double dst_y_per_row_flip; + double max_dst_y_per_vm_vblank; + double max_dst_y_per_row_vblank; + double vratio_pre_l; + double vratio_pre_c; + unsigned int req_per_swath_ub_l; + unsigned int req_per_swath_ub_c; + unsigned int meta_row_height_l; + unsigned int meta_row_height_c; + unsigned int swath_width_pixels_ub_l; + unsigned int swath_width_pixels_ub_c; + unsigned int scaler_rec_in_width_l; + unsigned int scaler_rec_in_width_c; + unsigned int dpte_row_height_l; + unsigned int dpte_row_height_c; + double hscale_pixel_rate_l; + double hscale_pixel_rate_c; + double min_hratio_fact_l; + double min_hratio_fact_c; + double refcyc_per_line_delivery_pre_l; + double refcyc_per_line_delivery_pre_c; + double refcyc_per_line_delivery_l; + double refcyc_per_line_delivery_c; + + double refcyc_per_req_delivery_pre_l; + double refcyc_per_req_delivery_pre_c; + double refcyc_per_req_delivery_l; + double refcyc_per_req_delivery_c; + + unsigned int full_recout_width; + double refcyc_per_req_delivery_pre_cur0; + double refcyc_per_req_delivery_cur0; + double refcyc_per_req_delivery_pre_cur1; + double refcyc_per_req_delivery_cur1; + int unsigned vba__min_dst_y_next_start = get_min_dst_y_next_start(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // FROM VBA + int unsigned vba__vready_after_vcount0 = get_vready_at_or_after_vsync(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + + float vba__refcyc_per_line_delivery_pre_l = get_refcyc_per_line_delivery_pre_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + float vba__refcyc_per_line_delivery_l = get_refcyc_per_line_delivery_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + float vba__refcyc_per_req_delivery_pre_l = get_refcyc_per_req_delivery_pre_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + float vba__refcyc_per_req_delivery_l = get_refcyc_per_req_delivery_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs)); + memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs)); + + dml_print("DML_DLG: %s: cstate_en = %d\n", __func__, cstate_en); + dml_print("DML_DLG: %s: pstate_en = %d\n", __func__, pstate_en); + dml_print("DML_DLG: %s: vm_en = %d\n", __func__, vm_en); + dml_print("DML_DLG: %s: ignore_viewport_pos = %d\n", __func__, ignore_viewport_pos); + dml_print("DML_DLG: %s: immediate_flip_support = %d\n", __func__, immediate_flip_support); + + dml_print("DML_DLG: %s: dppclk_freq_in_mhz = %3.2f\n", __func__, dppclk_freq_in_mhz); + dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); + dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); + dml_print("DML_DLG: %s: interlaced = %d\n", __func__, interlaced); ASSERT(ref_freq_to_pix_freq < 4.0); + + disp_dlg_regs->ref_freq_to_pix_freq = (unsigned int) (ref_freq_to_pix_freq * dml_pow(2, 19)); + disp_dlg_regs->refcyc_per_htotal = (unsigned int) (ref_freq_to_pix_freq * (double) htotal * dml_pow(2, 8)); + disp_dlg_regs->dlg_vblank_end = interlaced ? (vblank_end / 2) : vblank_end; // 15 bits + + //set_prefetch_mode(mode_lib, cstate_en, pstate_en, ignore_viewport_pos, immediate_flip_support); + min_ttu_vblank = get_min_ttu_vblank_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + + dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start; + + disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start) * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)dml_pow(2, 18)); + + dml_print("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, min_ttu_vblank); + dml_print("DML_DLG: %s: min_dst_y_next_start = 0x%0x\n", __func__, disp_dlg_regs->min_dst_y_next_start); + dml_print("DML_DLG: %s: dlg_vblank_start = 0x%0x\n", __func__, dlg_vblank_start); + dml_print("DML_DLG: %s: ref_freq_to_pix_freq = %3.2f\n", __func__, ref_freq_to_pix_freq); + dml_print("DML_DLG: %s: vba__min_dst_y_next_start = 0x%0x\n", __func__, vba__min_dst_y_next_start); + + //old_impl_vs_vba_impl("min_dst_y_next_start", dlg_vblank_start, vba__min_dst_y_next_start); + + // ------------------------- + // Section 1.15.2.2: Prefetch, Active and TTU + // ------------------------- + // Prefetch Calc + // Source + dual_plane = is_dual_plane((enum source_format_class) (src->source_format)); + mode_422 = 0; + access_dir = (src->source_scan == dm_vert); // vp access direction: horizontal or vertical accessed + vp_height_l = src->viewport_height; + vp_width_l = src->viewport_width; + vp_height_c = src->viewport_height_c; + vp_width_c = src->viewport_width_c; + + // Scaling + htaps_l = taps->htaps; + htaps_c = taps->htaps_c; + hratio_l = scl->hscl_ratio; + hratio_c = scl->hscl_ratio_c; + vratio_l = scl->vscl_ratio; + vratio_c = scl->vscl_ratio_c; + scl_enable = scl->scl_enable; + + swath_width_ub_l = rq_dlg_param.rq_l.swath_width_ub; + dpte_groups_per_row_ub_l = rq_dlg_param.rq_l.dpte_groups_per_row_ub; + swath_width_ub_c = rq_dlg_param.rq_c.swath_width_ub; + dpte_groups_per_row_ub_c = rq_dlg_param.rq_c.dpte_groups_per_row_ub; + + meta_chunks_per_row_ub_l = rq_dlg_param.rq_l.meta_chunks_per_row_ub; + meta_chunks_per_row_ub_c = rq_dlg_param.rq_c.meta_chunks_per_row_ub; + vupdate_offset = dst->vupdate_offset; + vupdate_width = dst->vupdate_width; + vready_offset = dst->vready_offset; + + dppclk_delay_subtotal = mode_lib->ip.dppclk_delay_subtotal; + dispclk_delay_subtotal = mode_lib->ip.dispclk_delay_subtotal; + + if (scl_enable) + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl; + else + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl_lb_only; + + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_cnvc_formatter + src->num_cursors * mode_lib->ip.dppclk_delay_cnvc_cursor; + + if (dout->dsc_enable) { + double dsc_delay = get_dsc_delay(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // FROM VBA + dispclk_delay_subtotal += dsc_delay; + } + + vstartup_start = dst->vstartup_start; + if (interlaced) { + if (vstartup_start / 2.0 - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal <= vblank_end / 2.0) + disp_dlg_regs->vready_after_vcount0 = 1; + else + disp_dlg_regs->vready_after_vcount0 = 0; + } else { + if (vstartup_start - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal <= vblank_end) + disp_dlg_regs->vready_after_vcount0 = 1; + else + disp_dlg_regs->vready_after_vcount0 = 0; + } + + dml_print("DML_DLG: %s: vready_after_vcount0 = %d\n", __func__, disp_dlg_regs->vready_after_vcount0); + dml_print("DML_DLG: %s: vba__vready_after_vcount0 = %d\n", __func__, vba__vready_after_vcount0); + //old_impl_vs_vba_impl("vready_after_vcount0", disp_dlg_regs->vready_after_vcount0, vba__vready_after_vcount0); + + if (interlaced) + vstartup_start = vstartup_start / 2; + + dst_x_after_scaler = get_dst_x_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + dst_y_after_scaler = get_dst_y_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + + // do some adjustment on the dst_after scaler to account for odm combine mode + dml_print("DML_DLG: %s: input dst_x_after_scaler = %d\n", __func__, dst_x_after_scaler); + dml_print("DML_DLG: %s: input dst_y_after_scaler = %d\n", __func__, dst_y_after_scaler); + + // need to figure out which side of odm combine we're in + if (dst->odm_combine) { + // figure out which pipes go together + bool visited[DC__NUM_PIPES__MAX]; + unsigned int i, j, k; + + for (k = 0; k < num_pipes; ++k) { + visited[k] = false; + pipe_index_in_combine[k] = 0; + } + + for (i = 0; i < num_pipes; i++) { + if (e2e_pipe_param[i].pipe.src.is_hsplit && !visited[i]) { + + unsigned int grp = e2e_pipe_param[i].pipe.src.hsplit_grp; + unsigned int grp_idx = 0; + + for (j = i; j < num_pipes; j++) { + if (e2e_pipe_param[j].pipe.src.hsplit_grp == grp && e2e_pipe_param[j].pipe.src.is_hsplit && !visited[j]) { + pipe_index_in_combine[j] = grp_idx; + dml_print("DML_DLG: %s: pipe[%d] is in grp %d idx %d\n", __func__, j, grp, grp_idx); + grp_idx++; + visited[j] = true; + } + } + } + } + + } + + if (dst->odm_combine == dm_odm_combine_mode_disabled) { + disp_dlg_regs->refcyc_h_blank_end = (unsigned int) ((double) hblank_end * ref_freq_to_pix_freq); + } else { + unsigned int odm_combine_factor = (dst->odm_combine == dm_odm_combine_mode_2to1 ? 2 : 4); // TODO: We should really check that 4to1 is supported before setting it to 4 + unsigned int odm_pipe_index = pipe_index_in_combine[pipe_idx]; + disp_dlg_regs->refcyc_h_blank_end = (unsigned int) (((double) hblank_end + odm_pipe_index * (double) dst->hactive / odm_combine_factor) * ref_freq_to_pix_freq); + } ASSERT(disp_dlg_regs->refcyc_h_blank_end < (unsigned int)dml_pow(2, 13)); + + dml_print("DML_DLG: %s: htotal = %d\n", __func__, htotal); + dml_print("DML_DLG: %s: dst_x_after_scaler[%d] = %d\n", __func__, pipe_idx, dst_x_after_scaler); + dml_print("DML_DLG: %s: dst_y_after_scaler[%d] = %d\n", __func__, pipe_idx, dst_y_after_scaler); + + dst_y_prefetch = get_dst_y_prefetch(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + dst_y_per_vm_vblank = get_dst_y_per_vm_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + dst_y_per_row_vblank = get_dst_y_per_row_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + dst_y_per_vm_flip = get_dst_y_per_vm_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + dst_y_per_row_flip = get_dst_y_per_row_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + + max_dst_y_per_vm_vblank = 32.0; //U5.2 + max_dst_y_per_row_vblank = 16.0; //U4.2 + + // magic! + if (htotal <= 75) { + max_dst_y_per_vm_vblank = 100.0; + max_dst_y_per_row_vblank = 100.0; + } + + dml_print("DML_DLG: %s: dst_y_prefetch (after rnd) = %3.2f\n", __func__, dst_y_prefetch); + dml_print("DML_DLG: %s: dst_y_per_vm_flip = %3.2f\n", __func__, dst_y_per_vm_flip); + dml_print("DML_DLG: %s: dst_y_per_row_flip = %3.2f\n", __func__, dst_y_per_row_flip); + dml_print("DML_DLG: %s: dst_y_per_vm_vblank = %3.2f\n", __func__, dst_y_per_vm_vblank); + dml_print("DML_DLG: %s: dst_y_per_row_vblank = %3.2f\n", __func__, dst_y_per_row_vblank); + + ASSERT(dst_y_per_vm_vblank < max_dst_y_per_vm_vblank); ASSERT(dst_y_per_row_vblank < max_dst_y_per_row_vblank); + + ASSERT(dst_y_prefetch > (dst_y_per_vm_vblank + dst_y_per_row_vblank)); + + vratio_pre_l = get_vratio_prefetch_l(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + vratio_pre_c = get_vratio_prefetch_c(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA + + dml_print("DML_DLG: %s: vratio_pre_l = %3.2f\n", __func__, vratio_pre_l); + dml_print("DML_DLG: %s: vratio_pre_c = %3.2f\n", __func__, vratio_pre_c); + + // Active + req_per_swath_ub_l = rq_dlg_param.rq_l.req_per_swath_ub; + req_per_swath_ub_c = rq_dlg_param.rq_c.req_per_swath_ub; + meta_row_height_l = rq_dlg_param.rq_l.meta_row_height; + meta_row_height_c = rq_dlg_param.rq_c.meta_row_height; + swath_width_pixels_ub_l = 0; + swath_width_pixels_ub_c = 0; + scaler_rec_in_width_l = 0; + scaler_rec_in_width_c = 0; + dpte_row_height_l = rq_dlg_param.rq_l.dpte_row_height; + dpte_row_height_c = rq_dlg_param.rq_c.dpte_row_height; + + if (mode_422) { + swath_width_pixels_ub_l = swath_width_ub_l * 2; // *2 for 2 pixel per element + swath_width_pixels_ub_c = swath_width_ub_c * 2; + } else { + swath_width_pixels_ub_l = swath_width_ub_l * 1; + swath_width_pixels_ub_c = swath_width_ub_c * 1; + } + + hscale_pixel_rate_l = 0.; + hscale_pixel_rate_c = 0.; + min_hratio_fact_l = 1.0; + min_hratio_fact_c = 1.0; + + if (hratio_l <= 1) + min_hratio_fact_l = 2.0; + else if (htaps_l <= 6) { + if ((hratio_l * 2.0) > 4.0) + min_hratio_fact_l = 4.0; + else + min_hratio_fact_l = hratio_l * 2.0; + } else { + if (hratio_l > 4.0) + min_hratio_fact_l = 4.0; + else + min_hratio_fact_l = hratio_l; + } + + hscale_pixel_rate_l = min_hratio_fact_l * dppclk_freq_in_mhz; + + dml_print("DML_DLG: %s: hratio_l = %3.2f\n", __func__, hratio_l); + dml_print("DML_DLG: %s: min_hratio_fact_l = %3.2f\n", __func__, min_hratio_fact_l); + dml_print("DML_DLG: %s: hscale_pixel_rate_l = %3.2f\n", __func__, hscale_pixel_rate_l); + + if (hratio_c <= 1) + min_hratio_fact_c = 2.0; + else if (htaps_c <= 6) { + if ((hratio_c * 2.0) > 4.0) + min_hratio_fact_c = 4.0; + else + min_hratio_fact_c = hratio_c * 2.0; + } else { + if (hratio_c > 4.0) + min_hratio_fact_c = 4.0; + else + min_hratio_fact_c = hratio_c; + } + + hscale_pixel_rate_c = min_hratio_fact_c * dppclk_freq_in_mhz; + + refcyc_per_line_delivery_pre_l = 0.; + refcyc_per_line_delivery_pre_c = 0.; + refcyc_per_line_delivery_l = 0.; + refcyc_per_line_delivery_c = 0.; + + refcyc_per_req_delivery_pre_l = 0.; + refcyc_per_req_delivery_pre_c = 0.; + refcyc_per_req_delivery_l = 0.; + refcyc_per_req_delivery_c = 0.; + + full_recout_width = 0; + // In ODM + if (src->is_hsplit) { + // This "hack" is only allowed (and valid) for MPC combine. In ODM + // combine, you MUST specify the full_recout_width...according to Oswin + if (dst->full_recout_width == 0 && !dst->odm_combine) { + dml_print("DML_DLG: %s: Warning: full_recout_width not set in hsplit mode\n", __func__); + full_recout_width = dst->recout_width * 2; // assume half split for dcn1 + } else + full_recout_width = dst->full_recout_width; + } else + full_recout_width = dst->recout_width; + + // As of DCN2, mpc_combine and odm_combine are mutually exclusive + refcyc_per_line_delivery_pre_l = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_l, + hscale_pixel_rate_l, + swath_width_pixels_ub_l, + 1); // per line + + refcyc_per_line_delivery_l = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_l, + hscale_pixel_rate_l, + swath_width_pixels_ub_l, + 1); // per line + + dml_print("DML_DLG: %s: full_recout_width = %d\n", __func__, full_recout_width); + dml_print("DML_DLG: %s: hscale_pixel_rate_l = %3.2f\n", __func__, hscale_pixel_rate_l); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_l = %3.2f\n", __func__, refcyc_per_line_delivery_pre_l); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_l = %3.2f\n", __func__, refcyc_per_line_delivery_l); + dml_print("DML_DLG: %s: vba__refcyc_per_line_delivery_pre_l = %3.2f\n", __func__, vba__refcyc_per_line_delivery_pre_l); + dml_print("DML_DLG: %s: vba__refcyc_per_line_delivery_l = %3.2f\n", __func__, vba__refcyc_per_line_delivery_l); + + //old_impl_vs_vba_impl("refcyc_per_line_delivery_pre_l", refcyc_per_line_delivery_pre_l, vba__refcyc_per_line_delivery_pre_l); + //old_impl_vs_vba_impl("refcyc_per_line_delivery_l", refcyc_per_line_delivery_l, vba__refcyc_per_line_delivery_l); + + if (dual_plane) { + float vba__refcyc_per_line_delivery_pre_c = get_refcyc_per_line_delivery_pre_c_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + float vba__refcyc_per_line_delivery_c = get_refcyc_per_line_delivery_c_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + refcyc_per_line_delivery_pre_c = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_c, + hscale_pixel_rate_c, + swath_width_pixels_ub_c, + 1); // per line + + refcyc_per_line_delivery_c = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_c, + hscale_pixel_rate_c, + swath_width_pixels_ub_c, + 1); // per line + + dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_c = %3.2f\n", __func__, refcyc_per_line_delivery_pre_c); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_c = %3.2f\n", __func__, refcyc_per_line_delivery_c); + dml_print("DML_DLG: %s: vba__refcyc_per_line_delivery_pre_c = %3.2f\n", __func__, vba__refcyc_per_line_delivery_pre_c); + dml_print("DML_DLG: %s: vba__refcyc_per_line_delivery_c = %3.2f\n", __func__, vba__refcyc_per_line_delivery_c); + + //old_impl_vs_vba_impl("refcyc_per_line_delivery_pre_c", refcyc_per_line_delivery_pre_c, vba__refcyc_per_line_delivery_pre_c); + //old_impl_vs_vba_impl("refcyc_per_line_delivery_c", refcyc_per_line_delivery_c, vba__refcyc_per_line_delivery_c); + } + + if (src->dynamic_metadata_enable && src->gpuvm) + disp_dlg_regs->refcyc_per_vm_dmdata = get_refcyc_per_vm_dmdata_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + disp_dlg_regs->dmdata_dl_delta = get_dmdata_dl_delta_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + // TTU - Luma / Chroma + if (access_dir) { // vertical access + scaler_rec_in_width_l = vp_height_l; + scaler_rec_in_width_c = vp_height_c; + } else { + scaler_rec_in_width_l = vp_width_l; + scaler_rec_in_width_c = vp_width_c; + } + + refcyc_per_req_delivery_pre_l = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_l, + hscale_pixel_rate_l, + scaler_rec_in_width_l, + req_per_swath_ub_l); // per req + + refcyc_per_req_delivery_l = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_l, + hscale_pixel_rate_l, + scaler_rec_in_width_l, + req_per_swath_ub_l); // per req + + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_l = %3.2f\n", __func__, refcyc_per_req_delivery_pre_l); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_l = %3.2f\n", __func__, refcyc_per_req_delivery_l); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_pre_l = %3.2f\n", __func__, vba__refcyc_per_req_delivery_pre_l); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_l = %3.2f\n", __func__, vba__refcyc_per_req_delivery_l); + + //old_impl_vs_vba_impl("refcyc_per_req_delivery_pre_l", refcyc_per_req_delivery_pre_l, vba__refcyc_per_req_delivery_pre_l); + //old_impl_vs_vba_impl("refcyc_per_req_delivery_l", refcyc_per_req_delivery_l, vba__refcyc_per_req_delivery_l); + + ASSERT(refcyc_per_req_delivery_pre_l < dml_pow(2, 13)); ASSERT(refcyc_per_req_delivery_l < dml_pow(2, 13)); + + if (dual_plane) { + float vba__refcyc_per_req_delivery_pre_c = get_refcyc_per_req_delivery_pre_c_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + float vba__refcyc_per_req_delivery_c = get_refcyc_per_req_delivery_c_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + refcyc_per_req_delivery_pre_c = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_c, + hscale_pixel_rate_c, + scaler_rec_in_width_c, + req_per_swath_ub_c); // per req + refcyc_per_req_delivery_c = get_refcyc_per_delivery( + mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_c, + hscale_pixel_rate_c, + scaler_rec_in_width_c, + req_per_swath_ub_c); // per req + + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_c = %3.2f\n", __func__, refcyc_per_req_delivery_pre_c); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_c = %3.2f\n", __func__, refcyc_per_req_delivery_c); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_pre_c = %3.2f\n", __func__, vba__refcyc_per_req_delivery_pre_c); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_c = %3.2f\n", __func__, vba__refcyc_per_req_delivery_c); + + //old_impl_vs_vba_impl("refcyc_per_req_delivery_pre_c", refcyc_per_req_delivery_pre_c, vba__refcyc_per_req_delivery_pre_c); + //old_impl_vs_vba_impl("refcyc_per_req_delivery_c", refcyc_per_req_delivery_c, vba__refcyc_per_req_delivery_c); + + ASSERT(refcyc_per_req_delivery_pre_c < dml_pow(2, 13)); ASSERT(refcyc_per_req_delivery_c < dml_pow(2, 13)); + } + + // TTU - Cursor + refcyc_per_req_delivery_pre_cur0 = 0.0; + refcyc_per_req_delivery_cur0 = 0.0; + + ASSERT(src->num_cursors <= 1); + + if (src->num_cursors > 0) { + float vba__refcyc_per_req_delivery_pre_cur0; + float vba__refcyc_per_req_delivery_cur0; + + calculate_ttu_cursor( + mode_lib, + &refcyc_per_req_delivery_pre_cur0, + &refcyc_per_req_delivery_cur0, + refclk_freq_in_mhz, + ref_freq_to_pix_freq, + hscale_pixel_rate_l, + scl->hscl_ratio, + vratio_pre_l, + vratio_l, + src->cur0_src_width, + (enum cursor_bpp) (src->cur0_bpp)); + + vba__refcyc_per_req_delivery_pre_cur0 = get_refcyc_per_cursor_req_delivery_pre_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + vba__refcyc_per_req_delivery_cur0 = get_refcyc_per_cursor_req_delivery_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_cur0 = %3.2f\n", __func__, refcyc_per_req_delivery_pre_cur0); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_cur0 = %3.2f\n", __func__, refcyc_per_req_delivery_cur0); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_pre_cur0 = %3.2f\n", __func__, vba__refcyc_per_req_delivery_pre_cur0); + dml_print("DML_DLG: %s: vba__refcyc_per_req_delivery_cur0 = %3.2f\n", __func__, vba__refcyc_per_req_delivery_cur0); + + //old_impl_vs_vba_impl("refcyc_per_req_delivery_pre_cur0", refcyc_per_req_delivery_pre_cur0, vba__refcyc_per_req_delivery_pre_cur0); + //old_impl_vs_vba_impl("refcyc_per_req_delivery_cur0", refcyc_per_req_delivery_cur0, vba__refcyc_per_req_delivery_cur0); + } + + refcyc_per_req_delivery_pre_cur1 = 0.0; + refcyc_per_req_delivery_cur1 = 0.0; + + // TTU - Misc + // all hard-coded + + // Assignment to register structures + disp_dlg_regs->dst_y_after_scaler = dst_y_after_scaler; // in terms of line + ASSERT(disp_dlg_regs->dst_y_after_scaler < (unsigned int)8); + disp_dlg_regs->refcyc_x_after_scaler = dst_x_after_scaler * ref_freq_to_pix_freq; // in terms of refclk + ASSERT(disp_dlg_regs->refcyc_x_after_scaler < (unsigned int)dml_pow(2, 13)); + disp_dlg_regs->dst_y_prefetch = (unsigned int) (dst_y_prefetch * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_vm_vblank = (unsigned int) (dst_y_per_vm_vblank * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_row_vblank = (unsigned int) (dst_y_per_row_vblank * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_vm_flip = (unsigned int) (dst_y_per_vm_flip * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_row_flip = (unsigned int) (dst_y_per_row_flip * dml_pow(2, 2)); + + disp_dlg_regs->vratio_prefetch = (unsigned int) (vratio_pre_l * dml_pow(2, 19)); + disp_dlg_regs->vratio_prefetch_c = (unsigned int) (vratio_pre_c * dml_pow(2, 19)); + + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_vblank); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_vblank); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_flip); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_flip); + + // hack for FPGA + if (mode_lib->project == DML_PROJECT_DCN31_FPGA) { + if (disp_dlg_regs->vratio_prefetch >= (unsigned int) dml_pow(2, 22)) { + disp_dlg_regs->vratio_prefetch = (unsigned int) dml_pow(2, 22) - 1; + dml_print("vratio_prefetch exceed the max value, the register field is [21:0]\n"); + } + } + + disp_dlg_regs->refcyc_per_pte_group_vblank_l = (unsigned int) (dst_y_per_row_vblank * (double) htotal * ref_freq_to_pix_freq / (double) dpte_groups_per_row_ub_l); + ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_l < (unsigned int)dml_pow(2, 13)); + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_vblank_c = (unsigned int) (dst_y_per_row_vblank * (double) htotal * ref_freq_to_pix_freq / (double) dpte_groups_per_row_ub_c); + ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_c < (unsigned int)dml_pow(2, 13)); + } + + disp_dlg_regs->refcyc_per_meta_chunk_vblank_l = (unsigned int) (dst_y_per_row_vblank * (double) htotal * ref_freq_to_pix_freq / (double) meta_chunks_per_row_ub_l); + ASSERT(disp_dlg_regs->refcyc_per_meta_chunk_vblank_l < (unsigned int)dml_pow(2, 13)); + + disp_dlg_regs->refcyc_per_meta_chunk_vblank_c = disp_dlg_regs->refcyc_per_meta_chunk_vblank_l; // dcc for 4:2:0 is not supported in dcn1.0. assigned to be the same as _l for now + + disp_dlg_regs->refcyc_per_pte_group_flip_l = (unsigned int) (dst_y_per_row_flip * htotal * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_l; + disp_dlg_regs->refcyc_per_meta_chunk_flip_l = (unsigned int) (dst_y_per_row_flip * htotal * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_l; + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_flip_c = (unsigned int) (dst_y_per_row_flip * htotal * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_c; + disp_dlg_regs->refcyc_per_meta_chunk_flip_c = (unsigned int) (dst_y_per_row_flip * htotal * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_c; + } + + disp_dlg_regs->refcyc_per_vm_group_vblank = get_refcyc_per_vm_group_vblank_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + disp_dlg_regs->refcyc_per_vm_group_flip = get_refcyc_per_vm_group_flip_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10); // From VBA + disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10); // From VBA + + // Clamp to max for now + if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_group_vblank = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_group_flip >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_group_flip = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_req_vblank >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_req_vblank = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_req_flip >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_req_flip = dml_pow(2, 23) - 1; + + disp_dlg_regs->dst_y_per_pte_row_nom_l = (unsigned int) ((double) dpte_row_height_l / (double) vratio_l * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->dst_y_per_pte_row_nom_l < (unsigned int)dml_pow(2, 17)); + if (dual_plane) { + disp_dlg_regs->dst_y_per_pte_row_nom_c = (unsigned int) ((double) dpte_row_height_c / (double) vratio_c * dml_pow(2, 2)); + if (disp_dlg_regs->dst_y_per_pte_row_nom_c >= (unsigned int) dml_pow(2, 17)) { + dml_print( + "DML_DLG: %s: Warning dst_y_per_pte_row_nom_c %u larger than supported by register format U15.2 %u\n", + __func__, + disp_dlg_regs->dst_y_per_pte_row_nom_c, + (unsigned int) dml_pow(2, 17) - 1); + } + } + + disp_dlg_regs->dst_y_per_meta_row_nom_l = (unsigned int) ((double) meta_row_height_l / (double) vratio_l * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->dst_y_per_meta_row_nom_l < (unsigned int)dml_pow(2, 17)); + + disp_dlg_regs->dst_y_per_meta_row_nom_c = (unsigned int) ((double) meta_row_height_c / (double) vratio_c * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->dst_y_per_meta_row_nom_c < (unsigned int)dml_pow(2, 17)); + + disp_dlg_regs->refcyc_per_pte_group_nom_l = (unsigned int) ((double) dpte_row_height_l / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq + / (double) dpte_groups_per_row_ub_l); + if (disp_dlg_regs->refcyc_per_pte_group_nom_l >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_pte_group_nom_l = dml_pow(2, 23) - 1; + disp_dlg_regs->refcyc_per_meta_chunk_nom_l = (unsigned int) ((double) meta_row_height_l / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq + / (double) meta_chunks_per_row_ub_l); + if (disp_dlg_regs->refcyc_per_meta_chunk_nom_l >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_meta_chunk_nom_l = dml_pow(2, 23) - 1; + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_nom_c = (unsigned int) ((double) dpte_row_height_c / (double) vratio_c * (double) htotal * ref_freq_to_pix_freq + / (double) dpte_groups_per_row_ub_c); + if (disp_dlg_regs->refcyc_per_pte_group_nom_c >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_pte_group_nom_c = dml_pow(2, 23) - 1; + + // TODO: Is this the right calculation? Does htotal need to be halved? + disp_dlg_regs->refcyc_per_meta_chunk_nom_c = (unsigned int) ((double) meta_row_height_c / (double) vratio_c * (double) htotal * ref_freq_to_pix_freq + / (double) meta_chunks_per_row_ub_c); + if (disp_dlg_regs->refcyc_per_meta_chunk_nom_c >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_meta_chunk_nom_c = dml_pow(2, 23) - 1; + } + + disp_dlg_regs->refcyc_per_line_delivery_pre_l = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_l, 1); + disp_dlg_regs->refcyc_per_line_delivery_l = (unsigned int) dml_floor(refcyc_per_line_delivery_l, 1); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_l < (unsigned int)dml_pow(2, 13)); ASSERT(disp_dlg_regs->refcyc_per_line_delivery_l < (unsigned int)dml_pow(2, 13)); + + disp_dlg_regs->refcyc_per_line_delivery_pre_c = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_c, 1); + disp_dlg_regs->refcyc_per_line_delivery_c = (unsigned int) dml_floor(refcyc_per_line_delivery_c, 1); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_c < (unsigned int)dml_pow(2, 13)); ASSERT(disp_dlg_regs->refcyc_per_line_delivery_c < (unsigned int)dml_pow(2, 13)); + + disp_dlg_regs->chunk_hdl_adjust_cur0 = 3; + disp_dlg_regs->dst_y_offset_cur0 = 0; + disp_dlg_regs->chunk_hdl_adjust_cur1 = 3; + disp_dlg_regs->dst_y_offset_cur1 = 0; + + disp_dlg_regs->dst_y_delta_drq_limit = 0x7fff; // off + + disp_ttu_regs->refcyc_per_req_delivery_pre_l = (unsigned int) (refcyc_per_req_delivery_pre_l * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_l = (unsigned int) (refcyc_per_req_delivery_l * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_c = (unsigned int) (refcyc_per_req_delivery_pre_c * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_c = (unsigned int) (refcyc_per_req_delivery_c * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_cur0 = (unsigned int) (refcyc_per_req_delivery_pre_cur0 * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_cur0 = (unsigned int) (refcyc_per_req_delivery_cur0 * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_cur1 = (unsigned int) (refcyc_per_req_delivery_pre_cur1 * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_cur1 = (unsigned int) (refcyc_per_req_delivery_cur1 * dml_pow(2, 10)); + + disp_ttu_regs->qos_level_low_wm = 0; + ASSERT(disp_ttu_regs->qos_level_low_wm < dml_pow(2, 14)); + + disp_ttu_regs->qos_level_high_wm = (unsigned int) (4.0 * (double) htotal * ref_freq_to_pix_freq); + ASSERT(disp_ttu_regs->qos_level_high_wm < dml_pow(2, 14)); + + disp_ttu_regs->qos_level_flip = 14; + disp_ttu_regs->qos_level_fixed_l = 8; + disp_ttu_regs->qos_level_fixed_c = 8; + disp_ttu_regs->qos_level_fixed_cur0 = 8; + disp_ttu_regs->qos_ramp_disable_l = 0; + disp_ttu_regs->qos_ramp_disable_c = 0; + disp_ttu_regs->qos_ramp_disable_cur0 = 0; + + disp_ttu_regs->min_ttu_vblank = min_ttu_vblank * refclk_freq_in_mhz; + ASSERT(disp_ttu_regs->min_ttu_vblank < dml_pow(2, 24)); + + print__ttu_regs_st(mode_lib, *disp_ttu_regs); + print__dlg_regs_st(mode_lib, *disp_dlg_regs); +} + +void dml31_rq_dlg_get_dlg_reg( + struct display_mode_lib *mode_lib, + display_dlg_regs_st *dlg_regs, + display_ttu_regs_st *ttu_regs, + display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support) +{ + display_rq_params_st rq_param = {0}; + display_dlg_sys_params_st dlg_sys_param = {0}; + + // Get watermark and Tex. + dlg_sys_param.t_urg_wm_us = get_wm_urgent(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.deepsleep_dcfclk_mhz = get_clk_dcf_deepsleep(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.t_extra_us = get_urgent_extra_latency(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.mem_trip_us = get_wm_memory_trip(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.t_mclk_wm_us = get_wm_dram_clock_change(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.t_sr_wm_us = get_wm_stutter_enter_exit(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.total_flip_bw = get_total_immediate_flip_bw(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib, e2e_pipe_param, num_pipes); + + print__dlg_sys_params_st(mode_lib, dlg_sys_param); + + // system parameter calculation done + + dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx); + dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe); + dml_rq_dlg_get_dlg_params( + mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx, + dlg_regs, + ttu_regs, + rq_param.dlg, + dlg_sys_param, + cstate_en, + pstate_en, + vm_en, + ignore_viewport_pos, + immediate_flip_support); + dml_print("DML_DLG: Calculation for pipe[%d] end\n", pipe_idx); +} + diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h new file mode 100644 index 000000000000..adf8518f761f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h @@ -0,0 +1,69 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DML31_DISPLAY_RQ_DLG_CALC_H__ +#define __DML31_DISPLAY_RQ_DLG_CALC_H__ + +#include "../display_rq_dlg_helpers.h" + +struct display_mode_lib; + +// Function: dml_rq_dlg_get_rq_reg +// Main entry point for test to get the register values out of this DML class. +// This function calls <get_rq_param> and <extract_rq_regs> fucntions to calculate +// and then populate the rq_regs struct +// Input: +// pipe_param - pipe source configuration (e.g. vp, pitch, scaling, dest, etc.) +// Output: +// rq_regs - struct that holds all the RQ registers field value. +// See also: <display_rq_regs_st> +void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, + display_rq_regs_st *rq_regs, + const display_pipe_params_st pipe_param); + +// Function: dml_rq_dlg_get_dlg_reg +// Calculate and return DLG and TTU register struct given the system setting +// Output: +// dlg_regs - output DLG register struct +// ttu_regs - output DLG TTU register struct +// Input: +// e2e_pipe_param - "compacted" array of e2e pipe param struct +// num_pipes - num of active "pipe" or "route" +// pipe_idx - index that identifies the e2e_pipe_param that corresponding to this dlg +// cstate - 0: when calculate min_ttu_vblank it is assumed cstate is not required. 1: Normal mode, cstate is considered. +// Added for legacy or unrealistic timing tests. +void dml31_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, + display_dlg_regs_st *dlg_regs, + display_ttu_regs_st *ttu_regs, + display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index 1f7b6ddf3020..8a5bd919aec8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -33,6 +33,8 @@ #include "dcn21/display_rq_dlg_calc_21.h" #include "dcn30/display_mode_vba_30.h" #include "dcn30/display_rq_dlg_calc_30.h" +#include "dcn31/display_mode_vba_31.h" +#include "dcn31/display_rq_dlg_calc_31.h" #include "dml_logger.h" const struct dml_funcs dml20_funcs = { @@ -63,6 +65,13 @@ const struct dml_funcs dml30_funcs = { .rq_dlg_get_rq_reg = dml30_rq_dlg_get_rq_reg }; +const struct dml_funcs dml31_funcs = { + .validate = dml31_ModeSupportAndSystemConfigurationFull, + .recalculate = dml31_recalculate, + .rq_dlg_get_dlg_reg = dml31_rq_dlg_get_dlg_reg, + .rq_dlg_get_rq_reg = dml31_rq_dlg_get_rq_reg +}; + void dml_init_instance(struct display_mode_lib *lib, const struct _vcs_dpi_soc_bounding_box_st *soc_bb, const struct _vcs_dpi_ip_params_st *ip_params, @@ -84,6 +93,10 @@ void dml_init_instance(struct display_mode_lib *lib, case DML_PROJECT_DCN30: lib->funcs = dml30_funcs; break; + case DML_PROJECT_DCN31: + case DML_PROJECT_DCN31_FPGA: + lib->funcs = dml31_funcs; + break; default: break; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 6ae5df58a4fc..d42a0aeca6be 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -38,6 +38,8 @@ enum dml_project { DML_PROJECT_NAVI10v2, DML_PROJECT_DCN21, DML_PROJECT_DCN30, + DML_PROJECT_DCN31, + DML_PROJECT_DCN31_FPGA, }; struct display_mode_lib; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 2ece3690bfa3..64daa0507393 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -74,6 +74,8 @@ struct _vcs_dpi_soc_bounding_box_st { unsigned int num_states; double sr_exit_time_us; double sr_enter_plus_exit_time_us; + double sr_exit_z8_time_us; + double sr_enter_plus_exit_z8_time_us; double urgent_latency_us; double urgent_latency_pixel_data_only_us; double urgent_latency_pixel_mixed_with_vm_data_us; @@ -209,6 +211,12 @@ struct _vcs_dpi_ip_params_st { unsigned int is_line_buffer_bpp_fixed; unsigned int line_buffer_fixed_bpp; unsigned int dcc_supported; + unsigned int config_return_buffer_size_in_kbytes; + unsigned int compressed_buffer_segment_size_in_kbytes; + unsigned int meta_fifo_size_in_kentries; + unsigned int zero_size_buffer_entries; + unsigned int compbuf_reserved_space_64b; + unsigned int compbuf_reserved_space_zs; unsigned int IsLineBufferBppFixed; unsigned int LineBufferFixedBpp; @@ -253,6 +261,8 @@ struct _vcs_dpi_display_pipe_source_params_st { unsigned int viewport_y_c; unsigned int viewport_width_c; unsigned int viewport_height_c; + unsigned int viewport_width_max; + unsigned int viewport_height_max; unsigned int data_pitch; unsigned int data_pitch_c; unsigned int meta_pitch; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c index d764d784e279..d3b1b6d4ce2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -89,6 +89,10 @@ dml_get_attr_func(wm_memory_trip, mode_lib->vba.UrgentLatency); dml_get_attr_func(wm_writeback_urgent, mode_lib->vba.WritebackUrgentWatermark); dml_get_attr_func(wm_stutter_exit, mode_lib->vba.StutterExitWatermark); dml_get_attr_func(wm_stutter_enter_exit, mode_lib->vba.StutterEnterPlusExitWatermark); +dml_get_attr_func(wm_z8_stutter_exit, mode_lib->vba.Z8StutterExitWatermark); +dml_get_attr_func(wm_z8_stutter_enter_exit, mode_lib->vba.Z8StutterEnterPlusExitWatermark); +dml_get_attr_func(stutter_efficiency_z8, mode_lib->vba.Z8StutterEfficiency); +dml_get_attr_func(stutter_num_bursts_z8, mode_lib->vba.Z8NumberOfStutterBurstsPerFrame); dml_get_attr_func(wm_dram_clock_change, mode_lib->vba.DRAMClockChangeWatermark); dml_get_attr_func(wm_writeback_dram_clock_change, mode_lib->vba.WritebackDRAMClockChangeWatermark); dml_get_attr_func(stutter_efficiency, mode_lib->vba.StutterEfficiency); @@ -153,11 +157,12 @@ dml_get_pipe_attr_func(refcyc_per_meta_chunk_vblank_l_in_us, mode_lib->vba.TimeP dml_get_pipe_attr_func(refcyc_per_meta_chunk_vblank_c_in_us, mode_lib->vba.TimePerChromaMetaChunkVBlank); dml_get_pipe_attr_func(refcyc_per_meta_chunk_flip_l_in_us, mode_lib->vba.TimePerMetaChunkFlip); dml_get_pipe_attr_func(refcyc_per_meta_chunk_flip_c_in_us, mode_lib->vba.TimePerChromaMetaChunkFlip); - dml_get_pipe_attr_func(vstartup, mode_lib->vba.VStartup); dml_get_pipe_attr_func(vupdate_offset, mode_lib->vba.VUpdateOffsetPix); dml_get_pipe_attr_func(vupdate_width, mode_lib->vba.VUpdateWidthPix); dml_get_pipe_attr_func(vready_offset, mode_lib->vba.VReadyOffsetPix); +dml_get_pipe_attr_func(vready_at_or_after_vsync, mode_lib->vba.VREADY_AT_OR_AFTER_VSYNC); +dml_get_pipe_attr_func(min_dst_y_next_start, mode_lib->vba.MIN_DST_Y_NEXT_START); double get_total_immediate_flip_bytes( struct display_mode_lib *mode_lib, @@ -226,6 +231,14 @@ static void fetch_socbb_params(struct display_mode_lib *mode_lib) mode_lib->vba.WritebackLatency = soc->writeback_latency_us; mode_lib->vba.SRExitTime = soc->sr_exit_time_us; mode_lib->vba.SREnterPlusExitTime = soc->sr_enter_plus_exit_time_us; + mode_lib->vba.PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency = soc->pct_ideal_sdp_bw_after_urgent; + mode_lib->vba.PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelMixedWithVMData = soc->pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm; + mode_lib->vba.PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelDataOnly = soc->pct_ideal_dram_sdp_bw_after_urgent_pixel_only; + mode_lib->vba.PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly = soc->pct_ideal_dram_sdp_bw_after_urgent_vm_only; + mode_lib->vba.MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation = + soc->max_avg_sdp_bw_use_normal_percent; + mode_lib->vba.SRExitZ8Time = soc->sr_exit_z8_time_us; + mode_lib->vba.SREnterPlusExitZ8Time = soc->sr_enter_plus_exit_z8_time_us; mode_lib->vba.DRAMClockChangeLatency = soc->dram_clock_change_latency_us; mode_lib->vba.DummyPStateCheck = soc->dram_clock_change_latency_us == soc->dummy_pstate_latency_us; mode_lib->vba.DRAMClockChangeSupportsVActive = !soc->disable_dram_clock_change_vactive_support || @@ -300,6 +313,14 @@ static void fetch_ip_params(struct display_mode_lib *mode_lib) mode_lib->vba.MaxPSCLToLBThroughput = ip->max_pscl_lb_bw_pix_per_clk; mode_lib->vba.ROBBufferSizeInKByte = ip->rob_buffer_size_kbytes; mode_lib->vba.DETBufferSizeInKByte[0] = ip->det_buffer_size_kbytes; + mode_lib->vba.ConfigReturnBufferSizeInKByte = ip->config_return_buffer_size_in_kbytes; + mode_lib->vba.CompressedBufferSegmentSizeInkByte = ip->compressed_buffer_segment_size_in_kbytes; + mode_lib->vba.MetaFIFOSizeInKEntries = ip->meta_fifo_size_in_kentries; + mode_lib->vba.ZeroSizeBufferEntries = ip->zero_size_buffer_entries; + mode_lib->vba.COMPBUF_RESERVED_SPACE_64B = ip->compbuf_reserved_space_64b; + mode_lib->vba.COMPBUF_RESERVED_SPACE_ZS = ip->compbuf_reserved_space_zs; + mode_lib->vba.MaximumDSCBitsPerComponent = ip->maximum_dsc_bits_per_component; + mode_lib->vba.DSC422NativeSupport = ip->dsc422_native_support; mode_lib->vba.PixelChunkSizeInKByte = ip->pixel_chunk_size_kbytes; mode_lib->vba.MetaChunkSize = ip->meta_chunk_size_kbytes; @@ -389,7 +410,6 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) visited[j] = true; mode_lib->vba.pipe_plane[j] = mode_lib->vba.NumberOfActivePlanes; - mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes] = 1; mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] = (enum scan_direction_class) (src->source_scan); @@ -429,6 +449,9 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) mode_lib->vba.VTAPsChroma[mode_lib->vba.NumberOfActivePlanes] = taps->vtaps_c; mode_lib->vba.HTotal[mode_lib->vba.NumberOfActivePlanes] = dst->htotal; mode_lib->vba.VTotal[mode_lib->vba.NumberOfActivePlanes] = dst->vtotal; + mode_lib->vba.VFrontPorch[mode_lib->vba.NumberOfActivePlanes] = dst->vfront_porch; + mode_lib->vba.DCCFractionOfZeroSizeRequestsLuma[mode_lib->vba.NumberOfActivePlanes] = src->dcc_fraction_of_zs_req_luma; + mode_lib->vba.DCCFractionOfZeroSizeRequestsChroma[mode_lib->vba.NumberOfActivePlanes] = src->dcc_fraction_of_zs_req_chroma; mode_lib->vba.DCCEnable[mode_lib->vba.NumberOfActivePlanes] = src->dcc_use_global ? ip->dcc_supported : src->dcc && ip->dcc_supported; @@ -630,6 +653,19 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) } } } + if (src->viewport_width_max) { + int hdiv_c = src->source_format >= dm_420_8 && src->source_format <= dm_422_10 ? 2 : 1; + int vdiv_c = src->source_format >= dm_420_8 && src->source_format <= dm_420_12 ? 2 : 1; + + if (mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] > src->viewport_width_max) + mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width_max; + if (mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] > src->viewport_height_max) + mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height_max; + if (mode_lib->vba.ViewportWidthChroma[mode_lib->vba.NumberOfActivePlanes] > src->viewport_width_max / hdiv_c) + mode_lib->vba.ViewportWidthChroma[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width_max / hdiv_c; + if (mode_lib->vba.ViewportHeightChroma[mode_lib->vba.NumberOfActivePlanes] > src->viewport_height_max / vdiv_c) + mode_lib->vba.ViewportHeightChroma[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height_max / vdiv_c; + } if (pipes[k].pipe.src.immediate_flip) { mode_lib->vba.ImmediateFlipSupport = true; @@ -662,6 +698,11 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) } } + mode_lib->vba.UseUnboundedRequesting = dm_unbounded_requesting; + for (k = 0; k < mode_lib->vba.cache_num_pipes; ++k) { + if (pipes[k].pipe.src.unbounded_req_mode == 0) + mode_lib->vba.UseUnboundedRequesting = dm_unbounded_requesting_disable; + } // TODO: ODMCombineEnabled => 2 * DPPPerPlane...actually maybe not since all pipes are specified // Do we want the dscclk to automatically be halved? Guess not since the value is specified mode_lib->vba.SynchronizedVBlank = pipes[0].pipe.dest.synchronized_vblank_all_planes; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h index 86db86b7153e..d18a021d4d32 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -39,6 +39,10 @@ dml_get_attr_decl(wm_memory_trip); dml_get_attr_decl(wm_writeback_urgent); dml_get_attr_decl(wm_stutter_exit); dml_get_attr_decl(wm_stutter_enter_exit); +dml_get_attr_decl(wm_z8_stutter_exit); +dml_get_attr_decl(wm_z8_stutter_enter_exit); +dml_get_attr_decl(stutter_efficiency_z8); +dml_get_attr_decl(stutter_num_bursts_z8); dml_get_attr_decl(wm_dram_clock_change); dml_get_attr_decl(wm_writeback_dram_clock_change); dml_get_attr_decl(stutter_efficiency_no_vblank); @@ -102,6 +106,8 @@ dml_get_pipe_attr_decl(vstartup); dml_get_pipe_attr_decl(vupdate_offset); dml_get_pipe_attr_decl(vupdate_width); dml_get_pipe_attr_decl(vready_offset); +dml_get_pipe_attr_decl(vready_at_or_after_vsync); +dml_get_pipe_attr_decl(min_dst_y_next_start); double get_total_immediate_flip_bytes( struct display_mode_lib *mode_lib, @@ -923,6 +929,46 @@ struct vba_vars_st { bool ClampMinDCFCLK; bool AllowDramClockChangeOneDisplayVactive; + double MaxAveragePercentOfIdealFabricAndSDPPortBWDisplayCanUseInNormalSystemOperation; + double PercentOfIdealFabricAndSDPPortBWReceivedAfterUrgLatency; + double PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelMixedWithVMData; + double PercentOfIdealDRAMBWReceivedAfterUrgLatencyVMDataOnly; + double PercentOfIdealDRAMBWReceivedAfterUrgLatencyPixelDataOnly; + double SRExitZ8Time; + double SREnterPlusExitZ8Time; + double Z8StutterExitWatermark; + double Z8StutterEnterPlusExitWatermark; + double Z8StutterEfficiencyNotIncludingVBlank; + double Z8StutterEfficiency; + double DCCFractionOfZeroSizeRequestsLuma[DC__NUM_DPP__MAX]; + double DCCFractionOfZeroSizeRequestsChroma[DC__NUM_DPP__MAX]; + double UrgBurstFactorCursor[DC__NUM_DPP__MAX]; + double UrgBurstFactorLuma[DC__NUM_DPP__MAX]; + double UrgBurstFactorChroma[DC__NUM_DPP__MAX]; + double UrgBurstFactorCursorPre[DC__NUM_DPP__MAX]; + double UrgBurstFactorLumaPre[DC__NUM_DPP__MAX]; + double UrgBurstFactorChromaPre[DC__NUM_DPP__MAX]; + bool NotUrgentLatencyHidingPre[DC__NUM_DPP__MAX]; + bool LinkCapacitySupport[DC__NUM_DPP__MAX]; + bool VREADY_AT_OR_AFTER_VSYNC[DC__NUM_DPP__MAX]; + unsigned int MIN_DST_Y_NEXT_START[DC__NUM_DPP__MAX]; + unsigned int VFrontPorch[DC__NUM_DPP__MAX]; + int ConfigReturnBufferSizeInKByte; + enum unbounded_requesting_policy UseUnboundedRequesting; + int CompressedBufferSegmentSizeInkByte; + int CompressedBufferSizeInkByte; + int MetaFIFOSizeInKEntries; + int ZeroSizeBufferEntries; + int COMPBUF_RESERVED_SPACE_64B; + int COMPBUF_RESERVED_SPACE_ZS; + bool UnboundedRequestEnabled; + bool DSC422NativeSupport; + bool NoEnoughUrgentLatencyHiding; + bool NoEnoughUrgentLatencyHidingPre; + int NumberOfStutterBurstsPerFrame; + int Z8NumberOfStutterBurstsPerFrame; + unsigned int MaximumDSCBitsPerComponent; + unsigned int NotEnoughUrgentLatencyHidingA[DC__VOLTAGE_STATES][2]; }; bool CalculateMinAndMaxPrefetchMode( diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index 92280cc05e2d..dae8e489c8cf 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -53,8 +53,8 @@ */ struct gpio_service *dal_gpio_service_create( - enum dce_version dce_version_major, - enum dce_version dce_version_minor, + enum dce_version dce_version, + enum dce_environment dce_environment, struct dc_context *ctx) { struct gpio_service *service; @@ -67,14 +67,14 @@ struct gpio_service *dal_gpio_service_create( return NULL; } - if (!dal_hw_translate_init(&service->translate, dce_version_major, - dce_version_minor)) { + if (!dal_hw_translate_init(&service->translate, dce_version, + dce_environment)) { BREAK_TO_DEBUGGER(); goto failure_1; } - if (!dal_hw_factory_init(&service->factory, dce_version_major, - dce_version_minor)) { + if (!dal_hw_factory_init(&service->factory, dce_version, + dce_environment)) { BREAK_TO_DEBUGGER(); goto failure_1; } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index 5aa714e831dd..c5c840a06050 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -112,6 +112,7 @@ bool dal_hw_factory_init( case DCN_VERSION_3_01: case DCN_VERSION_3_02: case DCN_VERSION_3_03: + case DCN_VERSION_3_1: dal_hw_factory_dcn30_init(factory); return true; #endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 199a9dd0e0e3..4a9848308766 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -107,6 +107,7 @@ bool dal_hw_translate_init( case DCN_VERSION_3_01: case DCN_VERSION_3_02: case DCN_VERSION_3_03: + case DCN_VERSION_3_1: dal_hw_translate_dcn30_init(translate); return true; #endif diff --git a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c index 51855a2624cf..4233955e3c47 100644 --- a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c +++ b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c @@ -33,6 +33,7 @@ #include "core_types.h" #include "dc_link_ddc.h" #include "link_hwss.h" +#include "inc/link_dpcd.h" #define DC_LOGGER \ link->ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 81b92f20d5b6..45a6216dfa2a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -338,6 +338,7 @@ union pipe_update_flags { uint32_t scaler : 1; uint32_t viewport : 1; uint32_t plane_changed : 1; + uint32_t det_size : 1; } bits; uint32_t raw; }; @@ -365,6 +366,8 @@ struct pipe_ctx { struct _vcs_dpi_display_ttu_regs_st ttu_regs; struct _vcs_dpi_display_rq_regs_st rq_regs; struct _vcs_dpi_display_pipe_dest_params_st pipe_dlg_param; + int det_buffer_size_kb; + bool unbounded_req; #endif union pipe_update_flags update_flags; struct dwbc *dwbc; @@ -415,6 +418,7 @@ struct dcn_bw_output { struct dc_clocks clk; struct dcn_watermark_set watermarks; struct dcn_bw_writeback bw_writeback; + int compbuf_size_kb; }; union bw_output { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index ffc3f2c63db8..e2b58ec9912d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -30,11 +30,29 @@ #define LINK_TRAINING_RETRY_DELAY 50 /* ms */ #define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/ #define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/ +#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 +#define TRAINING_AUX_RD_INTERVAL 100 //us struct dc_link; struct dc_stream_state; struct dc_link_settings; +enum { + LINK_TRAINING_MAX_RETRY_COUNT = 5, + /* to avoid infinite loop where-in the receiver + * switches between different VS + */ + LINK_TRAINING_MAX_CR_RETRY = 100, + /* + * Some receivers fail to train on first try and are good + * on subsequent tries. 2 retries should be plenty. If we + * don't have a successful training then we don't expect to + * ever get one. + */ + LINK_TRAINING_MAX_VERIFY_RETRY = 2, + PEAK_FACTOR_X1000 = 1006, +}; + bool dp_verify_link_cap( struct dc_link *link, struct dc_link_settings *known_limit_link_setting, @@ -68,6 +86,10 @@ bool perform_link_training_with_retries( enum signal_type signal, bool do_fallback); +bool hpd_rx_irq_check_link_loss_status( + struct dc_link *link, + union hpd_irq_data *hpd_irq_dpcd_data); + bool is_mst_supported(struct dc_link *link); bool detect_dp_sink_caps(struct dc_link *link); @@ -88,8 +110,59 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); bool dp_overwrite_extended_receiver_cap(struct dc_link *link); void dpcd_set_source_specific_data(struct dc_link *link); +/* Write DPCD link configuration data. */ +enum dc_status dpcd_set_link_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings); +/* Write DPCD drive settings. */ +enum dc_status dpcd_set_lane_settings( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + uint32_t offset); +/* Read training status and adjustment requests from DPCD. */ +enum dc_status dp_get_lane_status_and_drive_settings( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + union lane_status *ln_status, + union lane_align_status_updated *ln_status_updated, + struct link_training_settings *req_settings, + uint32_t offset); + +void dp_wait_for_training_aux_rd_interval( + struct dc_link *link, + uint32_t wait_in_micro_secs); + +bool dp_is_cr_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); + +enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); + +bool dp_is_ch_eq_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); +bool dp_is_symbol_locked(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); +bool dp_is_interlane_aligned(union lane_align_status_updated align_status); + +bool dp_is_max_vs_reached( + const struct link_training_settings *lt_settings); -void dp_set_fec_ready(struct dc_link *link, bool ready); +void dp_update_drive_settings( + struct link_training_settings *dest, + struct link_training_settings src); + +uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval); + +enum dpcd_training_patterns + dc_dp_training_pattern_to_dpcd_training_pattern( + struct dc_link *link, + enum dc_dp_training_pattern pattern); + +uint8_t dc_dp_initialize_scrambling_data_symbols( + struct dc_link *link, + enum dc_dp_training_pattern pattern); + +enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready); void dp_set_fec_enable(struct dc_link *link, bool enable); bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable); @@ -97,6 +170,13 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable); bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx); bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable); +/* Initialize output parameter lt_settings. */ +void dp_decide_training_settings( + struct dc_link *link, + const struct dc_link_settings *link_setting, + const struct dc_link_training_overrides *overrides, + struct link_training_settings *lt_settings); + /* Convert PHY repeater count read from DPCD uint8_t. */ uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count); @@ -105,5 +185,10 @@ enum link_training_result dp_check_link_loss_status( struct dc_link *link, const struct link_training_settings *link_training_setting); +enum dc_status dpcd_configure_lttpr_mode( + struct dc_link *link, + struct link_training_settings *lt_settings); + enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings); +bool dp_retrieve_lttpr_cap(struct dc_link *link); #endif /* __DC_LINK_DP_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h index e8ce8c85adf1..142753644377 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h @@ -52,7 +52,8 @@ struct abm_funcs { unsigned int (*get_target_backlight)(struct abm *abm); bool (*init_abm_config)(struct abm *abm, const char *src, - unsigned int bytes); + unsigned int bytes, + unsigned int inst); }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 5dc8d02b40c3..a17e5de3b100 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -91,6 +91,7 @@ struct clk_limit_table_entry { unsigned int dispclk_mhz; unsigned int dppclk_mhz; unsigned int phyclk_mhz; + unsigned int wck_ratio; }; /* This table is contiguous */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 336c80a18175..0afa2364a986 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -29,11 +29,40 @@ #include "dc_types.h" #include "hw_shared.h" +enum phyd32clk_clock_source { + PHYD32CLKA, + PHYD32CLKB, + PHYD32CLKC, + PHYD32CLKD, + PHYD32CLKE, + PHYD32CLKF, + PHYD32CLKG, +}; + +enum physymclk_clock_source { + PHYSYMCLK_FORCE_SRC_SYMCLK, // Select symclk as source of clock which is output to PHY through DCIO. + PHYSYMCLK_FORCE_SRC_PHYD18CLK, // Select phyd18clk as the source of clock which is output to PHY through DCIO. + PHYSYMCLK_FORCE_SRC_PHYD32CLK, // Select phyd32clk as the source of clock which is output to PHY through DCIO. +}; + +enum hdmistreamclk_source { + REFCLK, // Selects REFCLK as source for hdmistreamclk. + DTBCLK0, // Selects DTBCLK0 as source for hdmistreamclk. +}; + +enum dentist_dispclk_change_mode { + DISPCLK_CHANGE_MODE_IMMEDIATE, + DISPCLK_CHANGE_MODE_RAMPING, +}; + struct dccg { struct dc_context *ctx; const struct dccg_funcs *funcs; int pipe_dppclk_khz[MAX_PIPES]; int ref_dppclk; + int dtbclk_khz[MAX_PIPES]; + int audio_dtbclk_khz; + int ref_dtbclk_khz; }; struct dccg_funcs { @@ -43,7 +72,34 @@ struct dccg_funcs { void (*get_dccg_ref_freq)(struct dccg *dccg, unsigned int xtalin_freq_inKhz, unsigned int *dccg_ref_freq_inKhz); + void (*set_fifo_errdet_ovr_en)(struct dccg *dccg, + bool en); + void (*otg_add_pixel)(struct dccg *dccg, + uint32_t otg_inst); + void (*otg_drop_pixel)(struct dccg *dccg, + uint32_t otg_inst); void (*dccg_init)(struct dccg *dccg); + + void (*set_physymclk)( + struct dccg *dccg, + int phy_inst, + enum physymclk_clock_source clk_src, + bool force_enable); + + void (*set_dtbclk_dto)( + struct dccg *dccg, + int dtbclk_inst, + int req_dtbclk_khz, + int num_odm_segments, + const struct dc_crtc_timing *timing); + + void (*set_audio_dtbclk_dto)( + struct dccg *dccg, + uint32_t req_audio_dtbclk_khz); + + void (*set_dispclk_change_mode)( + struct dccg *dccg, + enum dentist_dispclk_change_mode change_mode); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index d9fd28b34f2a..0638b337f143 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -152,6 +152,9 @@ struct hubbub_funcs { void (*force_pstate_change_control)(struct hubbub *hubbub, bool force, bool allow); void (*init_watermarks)(struct hubbub *hubbub); + void (*program_det_size)(struct hubbub *hubbub, int hubp_inst, unsigned det_buffer_size_in_kbyte); + void (*program_compbuf_size)(struct hubbub *hubbub, unsigned compbuf_size_kb, bool safe_to_increase); + void (*init_crb)(struct hubbub *hubbub); }; struct hubbub { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 80bc99500645..9eaf345aa2a1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -127,6 +127,12 @@ struct link_enc_state { }; +enum encoder_type_select { + ENCODER_TYPE_DIG = 0, + ENCODER_TYPE_HDMI_FRL = 1, + ENCODER_TYPE_DP_128B132B = 2 +}; + struct link_encoder_funcs { void (*read_state)( struct link_encoder *enc, struct link_enc_state *s); @@ -185,6 +191,10 @@ struct link_encoder_funcs { enum signal_type (*get_dig_mode)( struct link_encoder *enc); + void (*set_dio_phy_mux)( + struct link_encoder *enc, + enum encoder_type_select sel, + uint32_t hpo_inst); }; /* diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h index 2e2310f1901a..8798cfa11a4d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h @@ -33,6 +33,8 @@ struct dchub_init_data; struct cstate_pstate_watermarks_st { uint32_t cstate_exit_ns; + uint32_t cstate_exit_z8_ns; + uint32_t cstate_enter_plus_exit_z8_ns; uint32_t cstate_enter_plus_exit_ns; uint32_t pstate_change_ns; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 47c7e4c3a51b..564ea6a727b0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -237,6 +237,9 @@ struct stream_encoder_funcs { void (*dp_set_odm_combine)( struct stream_encoder *enc, bool odm_combine); + + uint32_t (*get_fifo_cal_average_level)( + struct stream_encoder *enc); }; #endif /* STREAM_ENCODER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 9ff68b67780c..03f47f23fb65 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -173,6 +173,7 @@ struct timing_generator_funcs { bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); + bool (*immediate_disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); void (*get_position)(struct timing_generator *tg, struct crtc_position *position); @@ -223,6 +224,8 @@ struct timing_generator_funcs { void (*enable_advanced_request)(struct timing_generator *tg, bool enable, const struct dc_crtc_timing *timing); void (*set_drr)(struct timing_generator *tg, const struct drr_params *params); + void (*set_vtotal_min_max)(struct timing_generator *optc, int vtotal_min, int vtotal_max); + void (*get_last_used_drr_vtotal)(struct timing_generator *optc, uint32_t *refresh_rate); void (*set_static_screen_control)(struct timing_generator *tg, uint32_t event_triggers, uint32_t num_frames); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h index 2947d1b15512..2a0db2b03047 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h @@ -162,9 +162,7 @@ struct scl_inits { struct fixed31_32 h; struct fixed31_32 h_c; struct fixed31_32 v; - struct fixed31_32 v_bot; struct fixed31_32 v_c; - struct fixed31_32 v_c_bot; }; struct scaler_data { @@ -173,8 +171,6 @@ struct scaler_data { struct scaling_taps taps; struct rect viewport; struct rect viewport_c; - struct rect viewport_unadjusted; - struct rect viewport_c_unadjusted; struct rect recout; struct scaling_ratios ratios; struct scl_inits inits; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 43284d410687..5ab008e62b82 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -235,6 +235,9 @@ struct hw_sequencer_funcs { enum dc_color_depth color_depth, const struct tg_color *solid_color, int width, int height, int offset); + + void (*z10_restore)(struct dc *dc); + void (*update_visual_confirm_color)(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, @@ -253,4 +256,17 @@ const uint16_t *find_color_matrix( enum dc_color_space color_space, uint32_t *array_size); +void get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); +void get_mpctree_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); +void get_surface_tile_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); #endif /* __DC_HW_SEQUENCER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h index 36e906bb6bfc..f7f7e4fff0c2 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h @@ -127,11 +127,6 @@ struct hwseq_private_funcs { const struct dc_stream_state *stream, struct dc_state *context); bool (*s0i3_golden_init_wa)(struct dc *dc); - void (*get_surface_visual_confirm_color)( - const struct pipe_ctx *pipe_ctx, - struct tg_color *color); - void (*get_hdr_visual_confirm_color)(struct pipe_ctx *pipe_ctx, - struct tg_color *color); void (*set_hdr_multiplier)(struct pipe_ctx *pipe_ctx); void (*verify_allow_pstate_change_high)(struct dc *dc); void (*program_pipe)(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h new file mode 100644 index 000000000000..d4d52ef1b165 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h @@ -0,0 +1,18 @@ +#ifndef __LINK_DPCD_H__ +#define __LINK_DPCD_H__ +#include <inc/core_status.h> +#include <dc_link.h> +#include <inc/link_hwss.h> + +enum dc_status core_link_read_dpcd( + struct dc_link *link, + uint32_t address, + uint8_t *data, + uint32_t size); + +enum dc_status core_link_write_dpcd( + struct dc_link *link, + uint32_t address, + const uint8_t *data, + uint32_t size); +#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 33590a728fc5..fc1d289bb9fe 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -26,20 +26,6 @@ #ifndef __DC_LINK_HWSS_H__ #define __DC_LINK_HWSS_H__ -#include "inc/core_status.h" - -enum dc_status core_link_read_dpcd( - struct dc_link *link, - uint32_t address, - uint8_t *data, - uint32_t size); - -enum dc_status core_link_write_dpcd( - struct dc_link *link, - uint32_t address, - const uint8_t *data, - uint32_t size); - struct gpio *get_hpd_gpio(struct dc_bios *dcb, struct graphics_object_id link_id, struct gpio_service *gpio_service); diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index e9fabb85741f..0d09181227c5 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -117,4 +117,13 @@ IRQ_DCN3_03 = irq_service_dcn303.o AMD_DAL_IRQ_DCN3_03 = $(addprefix $(AMDDALPATH)/dc/irq/dcn303/,$(IRQ_DCN3_03)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN3_03) + +############################################################################### +# DCN 31 +############################################################################### +IRQ_DCN31 = irq_service_dcn31.o + +AMD_DAL_IRQ_DCN31= $(addprefix $(AMDDALPATH)/dc/irq/dcn31/,$(IRQ_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN31) endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c new file mode 100644 index 000000000000..38e0ade60c7b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c @@ -0,0 +1,432 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "include/logger_interface.h" +#include "../dce110/irq_service_dce110.h" + + +#include "yellow_carp_offset.h" +#include "dcn/dcn_3_1_2_offset.h" +#include "dcn/dcn_3_1_2_sh_mask.h" + +#include "irq_service_dcn31.h" + +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" + +enum dc_irq_source to_dal_irq_source_dcn31( + struct irq_service *irq_service, + uint32_t src_id, + uint32_t ext_id) +{ + switch (src_id) { + case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK1; + case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK2; + case DCN_1_0__SRCID__DC_D3_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK3; + case DCN_1_0__SRCID__DC_D4_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK4; + case DCN_1_0__SRCID__DC_D5_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK5; + case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK6; + case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC1_VLINE0; + case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC2_VLINE0; + case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC3_VLINE0; + case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC4_VLINE0; + case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC5_VLINE0; + case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL: + return DC_IRQ_SOURCE_DC6_VLINE0; + case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP1; + case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP2; + case DCN_1_0__SRCID__HUBP2_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP3; + case DCN_1_0__SRCID__HUBP3_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP4; + case DCN_1_0__SRCID__HUBP4_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP5; + case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP6; + case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE1; + case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE2; + case DCN_1_0__SRCID__OTG2_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE3; + case DCN_1_0__SRCID__OTG3_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE4; + case DCN_1_0__SRCID__OTG4_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE5; + case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE6; + case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT: + return DC_IRQ_SOURCE_DMCUB_OUTBOX; + case DCN_1_0__SRCID__DC_HPD1_INT: + /* generic src_id for all HPD and HPDRX interrupts */ + switch (ext_id) { + case DCN_1_0__CTXID__DC_HPD1_INT: + return DC_IRQ_SOURCE_HPD1; + case DCN_1_0__CTXID__DC_HPD2_INT: + return DC_IRQ_SOURCE_HPD2; + case DCN_1_0__CTXID__DC_HPD3_INT: + return DC_IRQ_SOURCE_HPD3; + case DCN_1_0__CTXID__DC_HPD4_INT: + return DC_IRQ_SOURCE_HPD4; + case DCN_1_0__CTXID__DC_HPD5_INT: + return DC_IRQ_SOURCE_HPD5; + case DCN_1_0__CTXID__DC_HPD6_INT: + return DC_IRQ_SOURCE_HPD6; + case DCN_1_0__CTXID__DC_HPD1_RX_INT: + return DC_IRQ_SOURCE_HPD1RX; + case DCN_1_0__CTXID__DC_HPD2_RX_INT: + return DC_IRQ_SOURCE_HPD2RX; + case DCN_1_0__CTXID__DC_HPD3_RX_INT: + return DC_IRQ_SOURCE_HPD3RX; + case DCN_1_0__CTXID__DC_HPD4_RX_INT: + return DC_IRQ_SOURCE_HPD4RX; + case DCN_1_0__CTXID__DC_HPD5_RX_INT: + return DC_IRQ_SOURCE_HPD5RX; + case DCN_1_0__CTXID__DC_HPD6_RX_INT: + return DC_IRQ_SOURCE_HPD6RX; + default: + return DC_IRQ_SOURCE_INVALID; + } + break; + + default: + return DC_IRQ_SOURCE_INVALID; + } +} + +static bool hpd_ack( + struct irq_service *irq_service, + const struct irq_source_info *info) +{ + uint32_t addr = info->status_reg; + uint32_t value = dm_read_reg(irq_service->ctx, addr); + uint32_t current_status = + get_reg_field_value( + value, + HPD0_DC_HPD_INT_STATUS, + DC_HPD_SENSE_DELAYED); + + dal_irq_service_ack_generic(irq_service, info); + + value = dm_read_reg(irq_service->ctx, info->enable_reg); + + set_reg_field_value( + value, + current_status ? 0 : 1, + HPD0_DC_HPD_INT_CONTROL, + DC_HPD_INT_POLARITY); + + dm_write_reg(irq_service->ctx, info->enable_reg, value); + + return true; +} + +static const struct irq_source_info_funcs hpd_irq_info_funcs = { + .set = NULL, + .ack = hpd_ack +}; + +static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs pflip_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs vblank_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs outbox_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs vline0_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +/* compile time expand base address. */ +#define BASE(seg) \ + BASE_INNER(seg) + +#define SRI(reg_name, block, id)\ + BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_DMUB(reg_name)\ + BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define IRQ_REG_ENTRY(block, reg_num, reg1, mask1, reg2, mask2)\ + .enable_reg = SRI(reg1, block, reg_num),\ + .enable_mask = \ + block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ + .enable_value = {\ + block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ + ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + },\ + .ack_reg = SRI(reg2, block, reg_num),\ + .ack_mask = \ + block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ + .ack_value = \ + block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \ + +#define IRQ_REG_ENTRY_DMUB(reg1, mask1, reg2, mask2)\ + .enable_reg = SRI_DMUB(reg1),\ + .enable_mask = \ + reg1 ## __ ## mask1 ## _MASK,\ + .enable_value = {\ + reg1 ## __ ## mask1 ## _MASK,\ + ~reg1 ## __ ## mask1 ## _MASK \ + },\ + .ack_reg = SRI_DMUB(reg2),\ + .ack_mask = \ + reg2 ## __ ## mask2 ## _MASK,\ + .ack_value = \ + reg2 ## __ ## mask2 ## _MASK \ + +#define hpd_int_entry(reg_num)\ + [DC_IRQ_SOURCE_HPD1 + reg_num] = {\ + IRQ_REG_ENTRY(HPD, reg_num,\ + DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\ + DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\ + .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\ + .funcs = &hpd_irq_info_funcs\ + } + +#define hpd_rx_int_entry(reg_num)\ + [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\ + IRQ_REG_ENTRY(HPD, reg_num,\ + DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\ + DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\ + .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\ + .funcs = &hpd_rx_irq_info_funcs\ + } +#define pflip_int_entry(reg_num)\ + [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\ + IRQ_REG_ENTRY(HUBPREQ, reg_num,\ + DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\ + DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\ + .funcs = &pflip_irq_info_funcs\ + } + +/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +#define vupdate_no_lock_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\ + .funcs = &vupdate_no_lock_irq_info_funcs\ + } + +#define vblank_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ + .funcs = &vblank_irq_info_funcs\ + } + +#define vline0_int_entry(reg_num)\ + [DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\ + OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\ + .funcs = &vline0_irq_info_funcs\ + } +#define dmub_outbox_int_entry()\ + [DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\ + IRQ_REG_ENTRY_DMUB(\ + DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\ + DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX1_READY_INT_ACK),\ + .funcs = &outbox_irq_info_funcs\ + } + +#define dummy_irq_entry() \ + {\ + .funcs = &dummy_irq_info_funcs\ + } + +#define i2c_int_entry(reg_num) \ + [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry() + +#define dp_sink_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry() + +#define gpio_pad_int_entry(reg_num) \ + [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry() + +#define dc_underflow_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() + +static const struct irq_source_info_funcs dummy_irq_info_funcs = { + .set = dal_irq_service_dummy_set, + .ack = dal_irq_service_dummy_ack +}; + +static const struct irq_source_info +irq_source_info_dcn31[DAL_IRQ_SOURCES_NUMBER] = { + [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(), + hpd_int_entry(0), + hpd_int_entry(1), + hpd_int_entry(2), + hpd_int_entry(3), + hpd_int_entry(4), + hpd_rx_int_entry(0), + hpd_rx_int_entry(1), + hpd_rx_int_entry(2), + hpd_rx_int_entry(3), + hpd_rx_int_entry(4), + i2c_int_entry(1), + i2c_int_entry(2), + i2c_int_entry(3), + i2c_int_entry(4), + i2c_int_entry(5), + i2c_int_entry(6), + dp_sink_int_entry(1), + dp_sink_int_entry(2), + dp_sink_int_entry(3), + dp_sink_int_entry(4), + dp_sink_int_entry(5), + dp_sink_int_entry(6), + [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(), + pflip_int_entry(0), + pflip_int_entry(1), + pflip_int_entry(2), + pflip_int_entry(3), + [DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(), + [DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(), + [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(), + gpio_pad_int_entry(0), + gpio_pad_int_entry(1), + gpio_pad_int_entry(2), + gpio_pad_int_entry(3), + gpio_pad_int_entry(4), + gpio_pad_int_entry(5), + gpio_pad_int_entry(6), + gpio_pad_int_entry(7), + gpio_pad_int_entry(8), + gpio_pad_int_entry(9), + gpio_pad_int_entry(10), + gpio_pad_int_entry(11), + gpio_pad_int_entry(12), + gpio_pad_int_entry(13), + gpio_pad_int_entry(14), + gpio_pad_int_entry(15), + gpio_pad_int_entry(16), + gpio_pad_int_entry(17), + gpio_pad_int_entry(18), + gpio_pad_int_entry(19), + gpio_pad_int_entry(20), + gpio_pad_int_entry(21), + gpio_pad_int_entry(22), + gpio_pad_int_entry(23), + gpio_pad_int_entry(24), + gpio_pad_int_entry(25), + gpio_pad_int_entry(26), + gpio_pad_int_entry(27), + gpio_pad_int_entry(28), + gpio_pad_int_entry(29), + gpio_pad_int_entry(30), + dc_underflow_int_entry(1), + dc_underflow_int_entry(2), + dc_underflow_int_entry(3), + dc_underflow_int_entry(4), + dc_underflow_int_entry(5), + dc_underflow_int_entry(6), + [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), + [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), + vupdate_no_lock_int_entry(0), + vupdate_no_lock_int_entry(1), + vupdate_no_lock_int_entry(2), + vupdate_no_lock_int_entry(3), + vblank_int_entry(0), + vblank_int_entry(1), + vblank_int_entry(2), + vblank_int_entry(3), + vline0_int_entry(0), + vline0_int_entry(1), + vline0_int_entry(2), + vline0_int_entry(3), + [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(), + [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(), + dmub_outbox_int_entry(), +}; + +static const struct irq_service_funcs irq_service_funcs_dcn31 = { + .to_dal_irq_source = to_dal_irq_source_dcn31 +}; + +static void dcn31_irq_construct( + struct irq_service *irq_service, + struct irq_service_init_data *init_data) +{ + dal_irq_service_construct(irq_service, init_data); + + irq_service->info = irq_source_info_dcn31; + irq_service->funcs = &irq_service_funcs_dcn31; +} + +struct irq_service *dal_irq_service_dcn31_create( + struct irq_service_init_data *init_data) +{ + struct irq_service *irq_service = kzalloc(sizeof(*irq_service), + GFP_KERNEL); + + if (!irq_service) + return NULL; + + dcn31_irq_construct(irq_service, init_data); + return irq_service; +} diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.h b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.h new file mode 100644 index 000000000000..67efbfe9b7aa --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.h @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_IRQ_SERVICE_DCN31_H__ +#define __DAL_IRQ_SERVICE_DCN31_H__ + +#include "../irq_service.h" + +struct irq_service *dal_irq_service_dcn31_create( + struct irq_service_init_data *init_data); + +#endif /* __DAL_IRQ_SERVICE_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 79ff68c13902..abbf7ae584c9 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -73,6 +73,7 @@ extern "C" { /* Forward declarations */ struct dmub_srv; struct dmub_srv_common_regs; +struct dmub_srv_dcn31_regs; struct dmcub_trace_buf_entry; @@ -94,6 +95,7 @@ enum dmub_asic { DMUB_ASIC_DCN301, DMUB_ASIC_DCN302, DMUB_ASIC_DCN303, + DMUB_ASIC_DCN31, DMUB_ASIC_MAX, }; @@ -232,6 +234,32 @@ struct dmub_srv_hw_params { uint32_t psp_version; bool load_inst_const; bool skip_panel_power_sequence; + bool disable_z10; +}; + +/** + * struct dmub_diagnostic_data - Diagnostic data retrieved from DMCUB for + * debugging purposes, including logging, crash analysis, etc. + */ +struct dmub_diagnostic_data { + uint32_t dmcub_version; + uint32_t scratch[16]; + uint32_t pc; + uint32_t undefined_address_fault_addr; + uint32_t inst_fetch_fault_addr; + uint32_t data_write_fault_addr; + uint32_t inbox1_rptr; + uint32_t inbox1_wptr; + uint32_t inbox1_size; + uint32_t inbox0_rptr; + uint32_t inbox0_wptr; + uint32_t inbox0_size; + uint8_t is_dmcub_enabled : 1; + uint8_t is_dmcub_soft_reset : 1; + uint8_t is_dmcub_secure_reset : 1; + uint8_t is_traceport_en : 1; + uint8_t is_cw0_enabled : 1; + uint8_t is_cw6_enabled : 1; }; /** @@ -324,7 +352,10 @@ struct dmub_srv_hw_funcs { uint32_t (*get_gpint_response)(struct dmub_srv *dmub); + void (*send_inbox0_cmd)(struct dmub_srv *dmub, union dmub_inbox0_data_register data); uint32_t (*get_current_time)(struct dmub_srv *dmub); + + void (*get_diagnostic_data)(struct dmub_srv *dmub, struct dmub_diagnostic_data *dmub_oca); }; /** @@ -363,6 +394,7 @@ struct dmub_srv { /* private: internal use only */ const struct dmub_srv_common_regs *regs; + const struct dmub_srv_dcn31_regs *regs_dcn31; struct dmub_srv_base_funcs funcs; struct dmub_srv_hw_funcs hw_funcs; @@ -672,6 +704,8 @@ enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub, bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry); +bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data); + #if defined(__cplusplus) } #endif diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 0b351da48563..7c4734f905d9 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -47,10 +47,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0x992f4893d +#define DMUB_FW_VERSION_GIT_HASH 0xf3da2b656 #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 66 +#define DMUB_FW_VERSION_REVISION 71 #define DMUB_FW_VERSION_TEST 0 #define DMUB_FW_VERSION_VBIOS 0 #define DMUB_FW_VERSION_HOTFIX 0 @@ -117,12 +117,21 @@ /* Maximum number of planes on any ASIC. */ #define DMUB_MAX_PLANES 6 -#define DMUB_MAX_SUBVP_STREAMS 2 - /* Trace buffer offset for entry */ #define TRACE_BUFFER_ENTRY_OFFSET 16 /** + * + * PSR control version legacy + */ +#define DMUB_CMD_PSR_CONTROL_VERSION_UNKNOWN 0x0 +/** + * PSR control version with multi edp support + */ +#define DMUB_CMD_PSR_CONTROL_VERSION_1 0x1 + + +/** * ABM control version legacy */ #define DMUB_CMD_ABM_CONTROL_VERSION_UNKNOWN 0x0 @@ -300,6 +309,7 @@ struct dmcub_trace_buf_entry { * Current scratch register usage is as follows: * * SCRATCH0: FW Boot Status register + * SCRATCH5: LVTMA Status Register * SCRATCH15: FW Boot Options register */ @@ -326,6 +336,21 @@ enum dmub_fw_boot_status_bit { DMUB_FW_BOOT_STATUS_BIT_RESTORE_REQUIRED = (1 << 3), /**< 1 if driver should call restore */ }; +/* Register bit definition for SCRATCH5 */ +union dmub_lvtma_status { + struct { + uint32_t psp_ok : 1; + uint32_t edp_on : 1; + uint32_t reserved : 30; + } bits; + uint32_t all; +}; + +enum dmub_lvtma_status_bit { + DMUB_LVTMA_STATUS_BIT_PSP_OK = (1 << 0), + DMUB_LVTMA_STATUS_BIT_EDP_ON = (1 << 1), +}; + /** * union dmub_fw_boot_options - Boot option definitions for SCRATCH15 */ @@ -337,7 +362,7 @@ union dmub_fw_boot_options { uint32_t skip_phy_access : 1; /**< 1 if PHY access should be skipped */ uint32_t disable_clk_gate: 1; /**< 1 if clock gating should be disabled */ uint32_t skip_phy_init_panel_sequence: 1; /**< 1 to skip panel init seq */ - uint32_t reserved_unreleased: 1; /**< reserved for an unreleased feature */ + uint32_t z10_disable: 1; /**< 1 to disable z10 */ uint32_t reserved : 25; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ @@ -603,6 +628,22 @@ enum dmub_cmd_type { */ DMUB_CMD__OUTBOX1_ENABLE = 71, /** + * Command type used for all idle optimization commands. + */ + DMUB_CMD__IDLE_OPT = 72, + /** + * Command type used for all clock manager commands. + */ + DMUB_CMD__CLK_MGR = 73, + /** + * Command type used for all panel control commands. + */ + DMUB_CMD__PANEL_CNTL = 74, + /** + * Command type used for EDID CEA parsing + */ + DMUB_CMD__EDID_CEA = 79, + /** * Command type used for all VBIOS interface commands. */ DMUB_CMD__VBIOS = 128, @@ -620,10 +661,6 @@ enum dmub_out_cmd_type { * Command type used for DP AUX Reply data notification */ DMUB_OUT_CMD__DP_AUX_REPLY = 1, - /** - * Command type used for DP HPD event notification - */ - DMUB_OUT_CMD__DP_HPD_NOTIFY = 2, }; #pragma pack(push, 1) @@ -812,6 +849,51 @@ struct dmub_rb_cmd_mall { }; /** + * enum dmub_cmd_idle_opt_type - Idle optimization command type. + */ +enum dmub_cmd_idle_opt_type { + /** + * DCN hardware restore. + */ + DMUB_CMD__IDLE_OPT_DCN_RESTORE = 0, +}; + +/** + * struct dmub_rb_cmd_idle_opt_dcn_restore - DCN restore command data. + */ +struct dmub_rb_cmd_idle_opt_dcn_restore { + struct dmub_cmd_header header; /**< header */ +}; + +/** + * struct dmub_clocks - Clock update notification. + */ +struct dmub_clocks { + uint32_t dispclk_khz; /**< dispclk kHz */ + uint32_t dppclk_khz; /**< dppclk kHz */ + uint32_t dcfclk_khz; /**< dcfclk kHz */ + uint32_t dcfclk_deep_sleep_khz; /**< dcfclk deep sleep kHz */ +}; + +/** + * enum dmub_cmd_clk_mgr_type - Clock manager commands. + */ +enum dmub_cmd_clk_mgr_type { + /** + * Notify DMCUB of clock update. + */ + DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS = 0, +}; + +/** + * struct dmub_rb_cmd_clk_mgr_notify_clocks - Clock update notification. + */ +struct dmub_rb_cmd_clk_mgr_notify_clocks { + struct dmub_cmd_header header; /**< header */ + struct dmub_clocks clocks; /**< clock data */ +}; + +/** * struct dmub_cmd_digx_encoder_control_data - Encoder control data. */ struct dmub_cmd_digx_encoder_control_data { @@ -1315,9 +1397,15 @@ struct dmub_cmd_psr_copy_settings_data { */ uint8_t fec_enable_delay_in100us; /** - * Explicit padding to 4 byte boundary. + * PSR control version. + */ + uint8_t cmd_version; + /** + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 */ - uint8_t pad3[2]; + uint8_t panel_inst; }; /** @@ -1342,10 +1430,16 @@ struct dmub_cmd_psr_set_level_data { * 16-bit value dicated by driver that will enable/disable different functionality. */ uint16_t psr_level; + /** + * PSR control version. + */ + uint8_t cmd_version; /** - * Explicit padding to 4 byte boundary. + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 */ - uint8_t pad[2]; + uint8_t panel_inst; }; /** @@ -1362,6 +1456,23 @@ struct dmub_rb_cmd_psr_set_level { struct dmub_cmd_psr_set_level_data psr_set_level_data; }; +struct dmub_rb_cmd_psr_enable_data { + /** + * PSR control version. + */ + uint8_t cmd_version; + /** + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; +}; + /** * Definition of a DMUB_CMD__PSR_ENABLE command. * PSR enable/disable is controlled using the sub_type. @@ -1371,6 +1482,8 @@ struct dmub_rb_cmd_psr_enable { * Command header. */ struct dmub_cmd_header header; + + struct dmub_rb_cmd_psr_enable_data data; }; /** @@ -1381,6 +1494,20 @@ struct dmub_cmd_psr_set_version_data { * PSR version that FW should implement. */ enum psr_version version; + /** + * PSR control version. + */ + uint8_t cmd_version; + /** + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; }; /** @@ -1397,6 +1524,23 @@ struct dmub_rb_cmd_psr_set_version { struct dmub_cmd_psr_set_version_data psr_set_version_data; }; +struct dmub_cmd_psr_force_static_data { + /** + * PSR control version. + */ + uint8_t cmd_version; + /** + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; +}; + /** * Definition of a DMUB_CMD__PSR_FORCE_STATIC command. */ @@ -1405,6 +1549,10 @@ struct dmub_rb_cmd_psr_force_static { * Command header. */ struct dmub_cmd_header header; + /** + * Data passed from driver to FW in a DMUB_CMD__PSR_FORCE_STATIC command. + */ + struct dmub_cmd_psr_force_static_data psr_force_static_data; }; /** @@ -1479,7 +1627,6 @@ enum hw_lock_client { * Driver is the client of HW Lock Manager. */ HW_LOCK_CLIENT_DRIVER = 0, - HW_LOCK_CLIENT_SUBVP = 3, /** * Invalid client. */ @@ -1957,6 +2104,41 @@ struct dmub_rb_cmd_drr_update { }; /** + * enum dmub_cmd_panel_cntl_type - Panel control command. + */ +enum dmub_cmd_panel_cntl_type { + /** + * Initializes embedded panel hardware blocks. + */ + DMUB_CMD__PANEL_CNTL_HW_INIT = 0, + /** + * Queries backlight info for the embedded panel. + */ + DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO = 1, +}; + +/** + * struct dmub_cmd_panel_cntl_data - Panel control data. + */ +struct dmub_cmd_panel_cntl_data { + uint32_t inst; /**< panel instance */ + uint32_t current_backlight; /* in/out */ + uint32_t bl_pwm_cntl; /* in/out */ + uint32_t bl_pwm_period_cntl; /* in/out */ + uint32_t bl_pwm_ref_div1; /* in/out */ + uint8_t is_backlight_on : 1; /* in/out */ + uint8_t is_powered_on : 1; /* in/out */ +}; + +/** + * struct dmub_rb_cmd_panel_cntl - Panel control command. + */ +struct dmub_rb_cmd_panel_cntl { + struct dmub_cmd_header header; /**< header */ + struct dmub_cmd_panel_cntl_data data; /**< payload */ +}; + +/** * Data passed from driver to FW in a DMUB_CMD__VBIOS_LVTMA_CONTROL command. */ struct dmub_cmd_lvtma_control_data { @@ -1981,6 +2163,68 @@ struct dmub_rb_cmd_lvtma_control { }; /** + * Maximum number of bytes a chunk sent to DMUB for parsing + */ +#define DMUB_EDID_CEA_DATA_CHUNK_BYTES 8 + +/** + * Represent a chunk of CEA blocks sent to DMUB for parsing + */ +struct dmub_cmd_send_edid_cea { + uint16_t offset; /**< offset into the CEA block */ + uint8_t length; /**< number of bytes in payload to copy as part of CEA block */ + uint16_t total_length; /**< total length of the CEA block */ + uint8_t payload[DMUB_EDID_CEA_DATA_CHUNK_BYTES]; /**< data chunk of the CEA block */ + uint8_t pad[3]; /**< padding and for future expansion */ +}; + +/** + * Result of VSDB parsing from CEA block + */ +struct dmub_cmd_edid_cea_amd_vsdb { + uint8_t vsdb_found; /**< 1 if parsing has found valid AMD VSDB */ + uint8_t freesync_supported; /**< 1 if Freesync is supported */ + uint16_t amd_vsdb_version; /**< AMD VSDB version */ + uint16_t min_frame_rate; /**< Maximum frame rate */ + uint16_t max_frame_rate; /**< Minimum frame rate */ +}; + +/** + * Result of sending a CEA chunk + */ +struct dmub_cmd_edid_cea_ack { + uint16_t offset; /**< offset of the chunk into the CEA block */ + uint8_t success; /**< 1 if this sending of chunk succeeded */ + uint8_t pad; /**< padding and for future expansion */ +}; + +/** + * Specify whether the result is an ACK/NACK or the parsing has finished + */ +enum dmub_cmd_edid_cea_reply_type { + DMUB_CMD__EDID_CEA_AMD_VSDB = 1, /**< VSDB parsing has finished */ + DMUB_CMD__EDID_CEA_ACK = 2, /**< acknowledges the CEA sending is OK or failing */ +}; + +/** + * Definition of a DMUB_CMD__EDID_CEA command. + */ +struct dmub_rb_cmd_edid_cea { + struct dmub_cmd_header header; /**< Command header */ + union dmub_cmd_edid_cea_data { + struct dmub_cmd_send_edid_cea input; /**< input to send CEA chunks */ + struct dmub_cmd_edid_cea_output { /**< output with results */ + uint8_t type; /**< dmub_cmd_edid_cea_reply_type */ + union { + struct dmub_cmd_edid_cea_amd_vsdb amd_vsdb; + struct dmub_cmd_edid_cea_ack ack; + }; + } output; /**< output to retrieve ACK/NACK or VSDB parsing results */ + } data; /**< Command data */ + +}; + +/** * union dmub_rb_cmd - DMUB inbox command. */ union dmub_rb_cmd { @@ -2054,6 +2298,20 @@ union dmub_rb_cmd { */ struct dmub_rb_cmd_mall mall; /** + * Definition of a DMUB_CMD__IDLE_OPT_DCN_RESTORE command. + */ + struct dmub_rb_cmd_idle_opt_dcn_restore dcn_restore; + + /** + * Definition of a DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS command. + */ + struct dmub_rb_cmd_clk_mgr_notify_clocks notify_clocks; + + /** + * Definition of DMUB_CMD__PANEL_CNTL commands. + */ + struct dmub_rb_cmd_panel_cntl panel_cntl; + /** * Definition of a DMUB_CMD__ABM_SET_PIPE command. */ struct dmub_rb_cmd_abm_set_pipe abm_set_pipe; @@ -2102,6 +2360,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__VBIOS_LVTMA_CONTROL command. */ struct dmub_rb_cmd_lvtma_control lvtma_control; + /** + * Definition of a DMUB_CMD__EDID_CEA command. + */ + struct dmub_rb_cmd_edid_cea edid_cea; }; /** diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile index 4d9387f53c77..0495bcdd3463 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/Makefile +++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile @@ -21,9 +21,8 @@ # DMUB = dmub_srv.o dmub_srv_stat.o dmub_reg.o dmub_dcn20.o dmub_dcn21.o -DMUB += dmub_dcn30.o dmub_dcn301.o -DMUB += dmub_dcn302.o -DMUB += dmub_dcn303.o +DMUB += dmub_dcn30.o dmub_dcn301.o dmub_dcn302.o dmub_dcn303.o +DMUB += dmub_dcn31.o AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB)) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c index 8cdc1c75394e..a6540e27044d 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -40,7 +40,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn20_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), @@ -404,3 +407,63 @@ uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub) { return REG_READ(DMCUB_TIMER_CURRENT); } + +void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) +{ + uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; + uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; + + if (!dmub || !diag_data) + return; + + memset(diag_data, 0, sizeof(*diag_data)); + + diag_data->dmcub_version = dmub->fw_version; + + diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + + diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + + diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + + diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); + diag_data->is_dmcub_enabled = is_dmub_enabled; + + REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &is_soft_reset); + diag_data->is_dmcub_soft_reset = is_soft_reset; + + REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); + diag_data->is_dmcub_secure_reset = is_sec_reset; + + REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); + diag_data->is_traceport_en = is_traceport_enabled; + + REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); + diag_data->is_cw0_enabled = is_cw0_enabled; + + REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); + diag_data->is_cw6_enabled = is_cw6_enabled; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h index f772f8b348ea..c2e5831ac52c 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -36,6 +36,9 @@ struct dmub_srv; DMUB_SR(DMCUB_CNTL) \ DMUB_SR(DMCUB_MEM_CNTL) \ DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX0_SIZE) \ + DMUB_SR(DMCUB_INBOX0_RPTR) \ + DMUB_SR(DMCUB_INBOX0_WPTR) \ DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ DMUB_SR(DMCUB_INBOX1_SIZE) \ DMUB_SR(DMCUB_INBOX1_RPTR) \ @@ -108,7 +111,12 @@ struct dmub_srv; DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ DMUB_SR(DCN_VM_FB_OFFSET) \ DMUB_SR(DMCUB_INTERRUPT_ACK) \ - DMUB_SR(DMCUB_TIMER_CURRENT) + DMUB_SR(DMCUB_TIMER_CURRENT) \ + DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \ + DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \ + DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR) + +#define DMCUB_INTERNAL_REGS() #define DMUB_COMMON_FIELDS() \ DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ @@ -118,6 +126,7 @@ struct dmub_srv; DMUB_SF(DMCUB_MEM_CNTL, DMCUB_MEM_WRITE_SPACE) \ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \ DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \ @@ -147,6 +156,7 @@ struct dmub_srv; struct dmub_srv_common_reg_offset { #define DMUB_SR(reg) uint32_t reg; DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() #undef DMUB_SR }; @@ -234,4 +244,6 @@ bool dmub_dcn20_use_cached_trace_buffer(struct dmub_srv *dmub); uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub); +void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *dmub_oca); + #endif /* _DMUB_DCN20_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c index 1cf67b3e4771..51bb9bceb1b1 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c @@ -39,7 +39,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn21_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c index fb11c8d39208..81dae75e9ff8 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c @@ -40,7 +40,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn30_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn301.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn301.c index 197398257692..84c3ab3becc5 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn301.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn301.c @@ -39,7 +39,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn301_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn302.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn302.c index f5db4437a882..8c02575e168d 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn302.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn302.c @@ -39,7 +39,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn302_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn303.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn303.c index 9331e1719901..b42369984473 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn303.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn303.c @@ -21,7 +21,10 @@ const struct dmub_srv_common_regs dmub_srv_dcn303_regs = { #define DMUB_SR(reg) REG_OFFSET(reg), - { DMUB_COMMON_REGS() }, + { + DMUB_COMMON_REGS() + DMCUB_INTERNAL_REGS() + }, #undef DMUB_SR #define DMUB_SF(reg, field) FD_MASK(reg, field), diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c new file mode 100644 index 000000000000..8c886ece71f6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -0,0 +1,354 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "../dmub_srv.h" +#include "dmub_reg.h" +#include "dmub_dcn31.h" + +#include "yellow_carp_offset.h" +#include "dcn/dcn_3_1_2_offset.h" +#include "dcn/dcn_3_1_2_sh_mask.h" + +#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg +#define CTX dmub +#define REGS dmub->regs_dcn31 +#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name) + +const struct dmub_srv_dcn31_regs dmub_srv_dcn31_regs = { +#define DMUB_SR(reg) REG_OFFSET_EXP(reg), + { DMUB_DCN31_REGS() }, +#undef DMUB_SR + +#define DMUB_SF(reg, field) FD_MASK(reg, field), + { DMUB_DCN31_FIELDS() }, +#undef DMUB_SF + +#define DMUB_SF(reg, field) FD_SHIFT(reg, field), + { DMUB_DCN31_FIELDS() }, +#undef DMUB_SF +}; + +static void dmub_dcn31_get_fb_base_offset(struct dmub_srv *dmub, + uint64_t *fb_base, + uint64_t *fb_offset) +{ + uint32_t tmp; + + if (dmub->fb_base || dmub->fb_offset) { + *fb_base = dmub->fb_base; + *fb_offset = dmub->fb_offset; + return; + } + + REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp); + *fb_base = (uint64_t)tmp << 24; + + REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp); + *fb_offset = (uint64_t)tmp << 24; +} + +static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in, + uint64_t fb_base, + uint64_t fb_offset, + union dmub_addr *addr_out) +{ + addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset; +} + +void dmub_dcn31_reset(struct dmub_srv *dmub) +{ + union dmub_gpint_data_register cmd; + const uint32_t timeout = 30; + uint32_t in_reset, scratch, i; + + REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset); + + if (in_reset == 0) { + cmd.bits.status = 1; + cmd.bits.command_code = DMUB_GPINT__STOP_FW; + cmd.bits.param = 0; + + dmub->hw_funcs.set_gpint(dmub, cmd); + + /** + * Timeout covers both the ACK and the wait + * for remaining work to finish. + * + * This is mostly bound by the PHY disable sequence. + * Each register check will be greater than 1us, so + * don't bother using udelay. + */ + + for (i = 0; i < timeout; ++i) { + if (dmub->hw_funcs.is_gpint_acked(dmub, cmd)) + break; + } + + for (i = 0; i < timeout; ++i) { + scratch = dmub->hw_funcs.get_gpint_response(dmub); + if (scratch == DMUB_GPINT__STOP_FW_RESPONSE) + break; + } + + /* Clear the GPINT command manually so we don't reset again. */ + cmd.all = 0; + dmub->hw_funcs.set_gpint(dmub, cmd); + + /* Force reset in case we timed out, DMCUB is likely hung. */ + } + + REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); + REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1); + REG_WRITE(DMCUB_INBOX1_RPTR, 0); + REG_WRITE(DMCUB_INBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); + REG_WRITE(DMCUB_SCRATCH0, 0); +} + +void dmub_dcn31_reset_release(struct dmub_srv *dmub) +{ + REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0); + REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); + REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); + REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0); +} + +void dmub_dcn31_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1) +{ + union dmub_addr offset; + uint64_t fb_base, fb_offset; + + dmub_dcn31_get_fb_base_offset(dmub, &fb_base, &fb_offset); + + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + + dmub_dcn31_translate_addr(&cw0->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); + REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, + DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, + DMCUB_REGION3_CW0_ENABLE, 1); + + dmub_dcn31_translate_addr(&cw1->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); + REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, + DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, + DMCUB_REGION3_CW1_ENABLE, 1); + + REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID, + 0x20); +} + +void dmub_dcn31_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6) +{ + union dmub_addr offset; + + offset = cw3->offset; + + REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base); + REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0, + DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top, + DMCUB_REGION3_CW3_ENABLE, 1); + + offset = cw4->offset; + + REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base); + REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0, + DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top, + DMCUB_REGION3_CW4_ENABLE, 1); + + offset = cw5->offset; + + REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base); + REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0, + DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top, + DMCUB_REGION3_CW5_ENABLE, 1); + + REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0, + DMCUB_REGION5_TOP_ADDRESS, + cw5->region.top - cw5->region.base - 1, + DMCUB_REGION5_ENABLE, 1); + + offset = cw6->offset; + + REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base); + REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0, + DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top, + DMCUB_REGION3_CW6_ENABLE, 1); +} + +void dmub_dcn31_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1) +{ + REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base); + REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base); +} + +uint32_t dmub_dcn31_get_inbox1_rptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_INBOX1_RPTR); +} + +void dmub_dcn31_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset) +{ + REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset); +} + +void dmub_dcn31_setup_out_mailbox(struct dmub_srv *dmub, + const struct dmub_region *outbox1) +{ + REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base); + REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base); +} + +uint32_t dmub_dcn31_get_outbox1_wptr(struct dmub_srv *dmub) +{ + /** + * outbox1 wptr register is accessed without locks (dal & dc) + * and to be called only by dmub_srv_stat_get_notification() + */ + return REG_READ(DMCUB_OUTBOX1_WPTR); +} + +void dmub_dcn31_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) +{ + /** + * outbox1 rptr register is accessed without locks (dal & dc) + * and to be called only by dmub_srv_stat_get_notification() + */ + REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset); +} + +bool dmub_dcn31_is_hw_init(struct dmub_srv *dmub) +{ + uint32_t is_hw_init; + + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init); + + return is_hw_init != 0; +} + +bool dmub_dcn31_is_supported(struct dmub_srv *dmub) +{ + uint32_t supported = 0; + + REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); + + return supported; +} + +void dmub_dcn31_set_gpint(struct dmub_srv *dmub, + union dmub_gpint_data_register reg) +{ + REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all); +} + +bool dmub_dcn31_is_gpint_acked(struct dmub_srv *dmub, + union dmub_gpint_data_register reg) +{ + union dmub_gpint_data_register test; + + reg.bits.status = 0; + test.all = REG_READ(DMCUB_GPINT_DATAIN1); + + return test.all == reg.all; +} + +uint32_t dmub_dcn31_get_gpint_response(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH7); +} + +union dmub_fw_boot_status dmub_dcn31_get_fw_boot_status(struct dmub_srv *dmub) +{ + union dmub_fw_boot_status status; + + status.all = REG_READ(DMCUB_SCRATCH0); + return status; +} + +void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) +{ + union dmub_fw_boot_options boot_options = {0}; + + boot_options.bits.z10_disable = params->disable_z10; + + REG_WRITE(DMCUB_SCRATCH14, boot_options.all); +} + +void dmub_dcn31_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip) +{ + union dmub_fw_boot_options boot_options; + boot_options.all = REG_READ(DMCUB_SCRATCH14); + boot_options.bits.skip_phy_init_panel_sequence = skip; + REG_WRITE(DMCUB_SCRATCH14, boot_options.all); +} + +void dmub_dcn31_setup_outbox0(struct dmub_srv *dmub, + const struct dmub_region *outbox0) +{ + REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base); + + REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base); +} + +uint32_t dmub_dcn31_get_outbox0_wptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_OUTBOX0_WPTR); +} + +void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) +{ + REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset); +} + +uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_TIMER_CURRENT); +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h new file mode 100644 index 000000000000..2829c3e9a310 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h @@ -0,0 +1,230 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_DCN31_H_ +#define _DMUB_DCN31_H_ + +#include "dmub_dcn20.h" + +struct dmub_srv; + +/* DCN31 register definitions. */ + +#define DMUB_DCN31_REGS() \ + DMUB_SR(DMCUB_CNTL) \ + DMUB_SR(DMCUB_CNTL2) \ + DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_INBOX1_SIZE) \ + DMUB_SR(DMCUB_INBOX1_RPTR) \ + DMUB_SR(DMCUB_INBOX1_WPTR) \ + DMUB_SR(DMCUB_OUTBOX0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX0_SIZE) \ + DMUB_SR(DMCUB_OUTBOX0_RPTR) \ + DMUB_SR(DMCUB_OUTBOX0_WPTR) \ + DMUB_SR(DMCUB_OUTBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX1_SIZE) \ + DMUB_SR(DMCUB_OUTBOX1_RPTR) \ + DMUB_SR(DMCUB_OUTBOX1_WPTR) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION4_OFFSET) \ + DMUB_SR(DMCUB_REGION4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION5_OFFSET) \ + DMUB_SR(DMCUB_REGION5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_SCRATCH0) \ + DMUB_SR(DMCUB_SCRATCH1) \ + DMUB_SR(DMCUB_SCRATCH2) \ + DMUB_SR(DMCUB_SCRATCH3) \ + DMUB_SR(DMCUB_SCRATCH4) \ + DMUB_SR(DMCUB_SCRATCH5) \ + DMUB_SR(DMCUB_SCRATCH6) \ + DMUB_SR(DMCUB_SCRATCH7) \ + DMUB_SR(DMCUB_SCRATCH8) \ + DMUB_SR(DMCUB_SCRATCH9) \ + DMUB_SR(DMCUB_SCRATCH10) \ + DMUB_SR(DMCUB_SCRATCH11) \ + DMUB_SR(DMCUB_SCRATCH12) \ + DMUB_SR(DMCUB_SCRATCH13) \ + DMUB_SR(DMCUB_SCRATCH14) \ + DMUB_SR(DMCUB_SCRATCH15) \ + DMUB_SR(DMCUB_GPINT_DATAIN1) \ + DMUB_SR(CC_DC_PIPE_DIS) \ + DMUB_SR(MMHUBBUB_SOFT_RESET) \ + DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ + DMUB_SR(DCN_VM_FB_OFFSET) \ + DMUB_SR(DMCUB_TIMER_CURRENT) + +#define DMUB_DCN31_FIELDS() \ + DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ + DMUB_SF(DMCUB_CNTL, DMCUB_TRACEPORT_EN) \ + DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_ENABLE) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_ENABLE) \ + DMUB_SF(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \ + DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \ + DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \ + DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) + +struct dmub_srv_dcn31_reg_offset { +#define DMUB_SR(reg) uint32_t reg; + DMUB_DCN31_REGS() +#undef DMUB_SR +}; + +struct dmub_srv_dcn31_reg_shift { +#define DMUB_SF(reg, field) uint8_t reg##__##field; + DMUB_DCN31_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_dcn31_reg_mask { +#define DMUB_SF(reg, field) uint32_t reg##__##field; + DMUB_DCN31_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_dcn31_regs { + const struct dmub_srv_dcn31_reg_offset offset; + const struct dmub_srv_dcn31_reg_mask mask; + const struct dmub_srv_dcn31_reg_shift shift; +}; + +extern const struct dmub_srv_dcn31_regs dmub_srv_dcn31_regs; + +/* Hardware functions. */ + + +void dmub_dcn31_init(struct dmub_srv *dmub); + +void dmub_dcn31_reset(struct dmub_srv *dmub); + +void dmub_dcn31_reset_release(struct dmub_srv *dmub); + +void dmub_dcn31_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn31_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6); + +void dmub_dcn31_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + +uint32_t dmub_dcn31_get_inbox1_rptr(struct dmub_srv *dmub); + +void dmub_dcn31_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset); + +void dmub_dcn31_setup_out_mailbox(struct dmub_srv *dmub, + const struct dmub_region *outbox1); + +uint32_t dmub_dcn31_get_outbox1_wptr(struct dmub_srv *dmub); + +void dmub_dcn31_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); + +bool dmub_dcn31_is_hw_init(struct dmub_srv *dmub); + +bool dmub_dcn31_is_supported(struct dmub_srv *dmub); + +void dmub_dcn31_set_gpint(struct dmub_srv *dmub, + union dmub_gpint_data_register reg); + +bool dmub_dcn31_is_gpint_acked(struct dmub_srv *dmub, + union dmub_gpint_data_register reg); + +uint32_t dmub_dcn31_get_gpint_response(struct dmub_srv *dmub); + +void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params); + +void dmub_dcn31_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip); + +union dmub_fw_boot_status dmub_dcn31_get_fw_boot_status(struct dmub_srv *dmub); + +void dmub_dcn31_setup_outbox0(struct dmub_srv *dmub, + const struct dmub_region *outbox0); + +uint32_t dmub_dcn31_get_outbox0_wptr(struct dmub_srv *dmub); + +void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); + +uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN31_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index f3f00d36e973..fd7e996ab1d7 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -31,6 +31,7 @@ #include "dmub_dcn301.h" #include "dmub_dcn302.h" #include "dmub_dcn303.h" +#include "dmub_dcn31.h" #include "os_types.h" /* * Note: the DMUB service is standalone. No additional headers should be @@ -173,6 +174,8 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr; funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr; + funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data; + if (asic == DMUB_ASIC_DCN21) { dmub->regs = &dmub_srv_dcn21_regs; @@ -204,6 +207,38 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) } break; + case DMUB_ASIC_DCN31: + funcs->reset = dmub_dcn31_reset; + funcs->reset_release = dmub_dcn31_reset_release; + funcs->backdoor_load = dmub_dcn31_backdoor_load; + funcs->setup_windows = dmub_dcn31_setup_windows; + funcs->setup_mailbox = dmub_dcn31_setup_mailbox; + funcs->get_inbox1_rptr = dmub_dcn31_get_inbox1_rptr; + funcs->set_inbox1_wptr = dmub_dcn31_set_inbox1_wptr; + funcs->setup_out_mailbox = dmub_dcn31_setup_out_mailbox; + funcs->get_outbox1_wptr = dmub_dcn31_get_outbox1_wptr; + funcs->set_outbox1_rptr = dmub_dcn31_set_outbox1_rptr; + funcs->is_supported = dmub_dcn31_is_supported; + funcs->is_hw_init = dmub_dcn31_is_hw_init; + funcs->set_gpint = dmub_dcn31_set_gpint; + funcs->is_gpint_acked = dmub_dcn31_is_gpint_acked; + funcs->get_gpint_response = dmub_dcn31_get_gpint_response; + funcs->get_fw_status = dmub_dcn31_get_fw_boot_status; + funcs->enable_dmub_boot_options = dmub_dcn31_enable_dmub_boot_options; + funcs->skip_dmub_panel_power_sequence = dmub_dcn31_skip_dmub_panel_power_sequence; + //outbox0 call stacks + funcs->setup_outbox0 = dmub_dcn31_setup_outbox0; + funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr; + funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr; + + if (asic == DMUB_ASIC_DCN31) { + dmub->regs_dcn31 = &dmub_srv_dcn31_regs; + } + + funcs->get_current_time = dmub_dcn31_get_current_time; + + break; + default: return false; } @@ -757,3 +792,11 @@ bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entr return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry); } + +bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) +{ + if (!dmub || !dmub->hw_funcs.get_diagnostic_data || !diag_data) + return false; + dmub->hw_funcs.get_diagnostic_data(dmub, diag_data); + return true; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c index e6f3bfab33d3..70766d534c9c 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c @@ -35,20 +35,13 @@ */ /** - ***************************************************************************** - * Function: dmub_srv_stat_get_notification + * dmub_srv_stat_get_notification - Retrieves a dmub outbox notification, set up dmub notification + * structure with message information. Also a pending bit if queue + * is having more notifications + * @dmub: dmub srv structure + * @notify: dmub notification structure to be filled up * - * @brief - * Retrieves a dmub outbox notification, set up dmub notification - * structure with message information. Also a pending bit if queue - * is having more notifications - * - * @param [in] dmub: dmub srv structure - * @param [out] pnotify: dmub notification structure to be filled up - * - * @return - * dmub_status - ***************************************************************************** + * Returns: dmub_status */ enum dmub_status dmub_srv_stat_get_notification(struct dmub_srv *dmub, struct dmub_notification *notify) diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index cb35eae29ca0..381c17caace1 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -224,6 +224,17 @@ enum { #define ASICREV_IS_GREEN_SARDINE(eChipRev) ((eChipRev >= GREEN_SARDINE_A0) && (eChipRev < 0xFF)) #endif +#define FAMILY_YELLOW_CARP 146 + +#define YELLOW_CARP_A0 0x01 +#define YELLOW_CARP_B0 0x02 // TODO: DCN31 - update with correct B0 ID +#define YELLOW_CARP_UNKNOWN 0xFF + +#ifndef ASICREV_IS_YELLOW_CARP +#define ASICREV_IS_YELLOW_CARP(eChipRev) ((eChipRev >= YELLOW_CARP_A0) && (eChipRev < YELLOW_CARP_UNKNOWN)) +#endif + + /* * ASIC chip ID */ diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h index 85aed509c01f..fe75ec834892 100644 --- a/drivers/gpu/drm/amd/display/include/dal_types.h +++ b/drivers/gpu/drm/amd/display/include/dal_types.h @@ -55,6 +55,7 @@ enum dce_version { DCN_VERSION_3_01, DCN_VERSION_3_02, DCN_VERSION_3_03, + DCN_VERSION_3_1, DCN_VERSION_MAX }; diff --git a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h index 9c55d247227e..7e3240e73c1f 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h @@ -42,8 +42,8 @@ void dal_gpio_destroy( struct gpio **ptr); struct gpio_service *dal_gpio_service_create( - enum dce_version dce_version_major, - enum dce_version dce_version_minor, + enum dce_version dce_version, + enum dce_environment dce_environment, struct dc_context *ctx); struct gpio *dal_gpio_service_create_irq( diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 7a30ca01e7d4..32f5274ed34e 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -85,6 +85,7 @@ struct link_training_settings { enum dc_voltage_swing *voltage_swing; enum dc_pre_emphasis *pre_emphasis; enum dc_post_cursor2 *post_cursor2; + bool should_set_fec_ready; uint16_t cr_pattern_time; uint16_t eq_pattern_time; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 3f4f44b44e6a..b99aa232bd8b 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -516,7 +516,8 @@ bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, } static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) + struct dc_info_packet *infopacket, + bool freesync_on_desktop) { /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ infopacket->sb[1] = 0x1A; @@ -542,10 +543,16 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, vrr->state != VRR_STATE_UNSUPPORTED) infopacket->sb[6] |= 0x02; - /* PB6 = [Bit 2 = FreeSync Active] */ - if (vrr->state != VRR_STATE_DISABLED && + if (freesync_on_desktop) { + /* PB6 = [Bit 2 = FreeSync Active] */ + if (vrr->state != VRR_STATE_DISABLED && vrr->state != VRR_STATE_UNSUPPORTED) - infopacket->sb[6] |= 0x04; + infopacket->sb[6] |= 0x04; + } else { + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || + vrr->state == VRR_STATE_ACTIVE_FIXED) + infopacket->sb[6] |= 0x04; + } // For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range /* PB7 = FreeSync Minimum refresh rate (Hz) */ @@ -824,13 +831,14 @@ static void build_vrr_infopacket_checksum(unsigned int *payload_size, static void build_vrr_infopacket_v1(enum signal_type signal, const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) + struct dc_info_packet *infopacket, + bool freesync_on_desktop) { /* SPD info packet for FreeSync */ unsigned int payload_size = 0; build_vrr_infopacket_header_v1(signal, infopacket, &payload_size); - build_vrr_infopacket_data_v1(vrr, infopacket); + build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop); build_vrr_infopacket_checksum(&payload_size, infopacket); infopacket->valid = true; @@ -839,12 +847,13 @@ static void build_vrr_infopacket_v1(enum signal_type signal, static void build_vrr_infopacket_v2(enum signal_type signal, const struct mod_vrr_params *vrr, enum color_transfer_func app_tf, - struct dc_info_packet *infopacket) + struct dc_info_packet *infopacket, + bool freesync_on_desktop) { unsigned int payload_size = 0; build_vrr_infopacket_header_v2(signal, infopacket, &payload_size); - build_vrr_infopacket_data_v1(vrr, infopacket); + build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop); build_vrr_infopacket_fs2_data(app_tf, infopacket); @@ -953,12 +962,12 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, #endif break; case PACKET_TYPE_FS_V2: - build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); + build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop); break; case PACKET_TYPE_VRR: case PACKET_TYPE_FS_V1: default: - build_vrr_infopacket_v1(stream->signal, vrr, infopacket); + build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop); } if (true == pack_sdp_v1_3 && diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c index 43e6f8b17e79..de872e7958b0 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c @@ -29,8 +29,10 @@ static inline enum mod_hdcp_status validate_bksv(struct mod_hdcp *hdcp) { uint64_t n = 0; uint8_t count = 0; + u8 bksv[sizeof(n)] = { }; - memcpy(&n, hdcp->auth.msg.hdcp1.bksv, sizeof(uint64_t)); + memcpy(bksv, hdcp->auth.msg.hdcp1.bksv, sizeof(hdcp->auth.msg.hdcp1.bksv)); + n = *(uint64_t *)bksv; while (n) { count++; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c index b0306ed6d6b4..70cb230d8f56 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c @@ -564,7 +564,7 @@ enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp, case D2_A5_AUTHENTICATED: if (input->rxstatus_read == FAIL || input->reauth_request_check == FAIL) { - fail_and_restart_in_ms(0, &status, output); + fail_and_restart_in_ms(100, &status, output); break; } else if (input->link_integrity_check_dp == FAIL) { if (hdcp->connection.hdcp2_retry_count >= 1) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c index ee5230ccf3c4..1a0f7c3dc964 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c @@ -172,6 +172,8 @@ char *mod_hdcp_status_to_str(int32_t status) return "MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE"; case MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE: return "MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE"; + case MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE: + return "MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE"; default: return "MOD_HDCP_STATUS_UNKNOWN"; } diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index 26f96c05e0ec..1b02056bc8bd 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -44,11 +44,12 @@ static void hdcp2_message_init(struct mod_hdcp *hdcp, in->process.msg3_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; in->process.msg3_desc.msg_size = 0; } -enum mod_hdcp_status mod_hdcp_remove_display_from_topology( + +static enum mod_hdcp_status mod_hdcp_remove_display_from_topology_v2( struct mod_hdcp *hdcp, uint8_t index) - { - struct psp_context *psp = hdcp->config.psp.handle; - struct ta_dtm_shared_memory *dtm_cmd; +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_dtm_shared_memory *dtm_cmd; struct mod_hdcp_display *display = get_active_display_at_index(hdcp, index); enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; @@ -79,8 +80,61 @@ enum mod_hdcp_status mod_hdcp_remove_display_from_topology( mutex_unlock(&psp->dtm_context.mutex); return status; } -enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp, - struct mod_hdcp_display *display) + +static enum mod_hdcp_status mod_hdcp_remove_display_from_topology_v3( + struct mod_hdcp *hdcp, uint8_t index) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_dtm_shared_memory *dtm_cmd; + struct mod_hdcp_display *display = + get_active_display_at_index(hdcp, index); + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf; + + if (!display || !is_display_active(display)) + return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; + + mutex_lock(&psp->dtm_context.mutex); + + memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory)); + + dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3; + dtm_cmd->dtm_in_message.topology_update_v3.display_handle = display->index; + dtm_cmd->dtm_in_message.topology_update_v3.is_active = 0; + dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE; + + psp_dtm_invoke(psp, dtm_cmd->cmd_id); + + if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { + status = mod_hdcp_remove_display_from_topology_v2(hdcp, index); + if (status != MOD_HDCP_STATUS_SUCCESS) + display->state = MOD_HDCP_DISPLAY_INACTIVE; + } else { + display->state = MOD_HDCP_DISPLAY_ACTIVE; + HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index); + } + + mutex_unlock(&psp->dtm_context.mutex); + + return status; +} + +enum mod_hdcp_status mod_hdcp_remove_display_from_topology( + struct mod_hdcp *hdcp, uint8_t index) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_UPDATE_TOPOLOGY_FAILURE; + + if (hdcp->config.psp.caps.dtm_v3_supported) + status = mod_hdcp_remove_display_from_topology_v3(hdcp, index); + else + status = mod_hdcp_remove_display_from_topology_v2(hdcp, index); + + return status; +} + +static enum mod_hdcp_status mod_hdcp_add_display_to_topology_v2( + struct mod_hdcp *hdcp, struct mod_hdcp_display *display) { struct psp_context *psp = hdcp->config.psp.handle; struct ta_dtm_shared_memory *dtm_cmd; @@ -126,6 +180,71 @@ enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp, return status; } +static enum mod_hdcp_status mod_hdcp_add_display_to_topology_v3( + struct mod_hdcp *hdcp, struct mod_hdcp_display *display) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_dtm_shared_memory *dtm_cmd; + struct mod_hdcp_link *link = &hdcp->connection.link; + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (!psp->dtm_context.dtm_initialized) { + DRM_INFO("Failed to add display topology, DTM TA is not initialized."); + display->state = MOD_HDCP_DISPLAY_INACTIVE; + return MOD_HDCP_STATUS_FAILURE; + } + + dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf; + + mutex_lock(&psp->dtm_context.mutex); + memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory)); + + dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3; + dtm_cmd->dtm_in_message.topology_update_v3.display_handle = display->index; + dtm_cmd->dtm_in_message.topology_update_v3.is_active = 1; + dtm_cmd->dtm_in_message.topology_update_v3.controller = display->controller; + dtm_cmd->dtm_in_message.topology_update_v3.ddc_line = link->ddc_line; + dtm_cmd->dtm_in_message.topology_update_v3.link_enc = link->link_enc_idx; + dtm_cmd->dtm_in_message.topology_update_v3.stream_enc = display->stream_enc_idx; + if (is_dp_hdcp(hdcp)) + dtm_cmd->dtm_in_message.topology_update_v3.is_assr = link->dp.assr_enabled; + + dtm_cmd->dtm_in_message.topology_update_v3.dp_mst_vcid = display->vc_id; + dtm_cmd->dtm_in_message.topology_update_v3.max_hdcp_supported_version = + TA_DTM_HDCP_VERSION_MAX_SUPPORTED__2_3; + dtm_cmd->dtm_in_message.topology_update_v3.encoder_type = TA_DTM_ENCODER_TYPE__DIG; + dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE; + dtm_cmd->dtm_in_message.topology_update_v3.phy_id = link->phy_idx; + dtm_cmd->dtm_in_message.topology_update_v3.link_hdcp_cap = link->hdcp_supported_informational; + + psp_dtm_invoke(psp, dtm_cmd->cmd_id); + + if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { + status = mod_hdcp_add_display_to_topology_v2(hdcp, display); + if (status != MOD_HDCP_STATUS_SUCCESS) + display->state = MOD_HDCP_DISPLAY_INACTIVE; + } else { + HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index); + } + + mutex_unlock(&psp->dtm_context.mutex); + + return status; +} + +enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp, + struct mod_hdcp_display *display) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (hdcp->config.psp.caps.dtm_v3_supported) + status = mod_hdcp_add_display_to_topology_v3(hdcp, display); + else + status = mod_hdcp_add_display_to_topology_v2(hdcp, display); + + return status; +} + enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp) { @@ -371,19 +490,6 @@ enum mod_hdcp_status mod_hdcp_hdcp1_link_maintenance(struct mod_hdcp *hdcp) return status; } -enum mod_hdcp_status mod_hdcp_hdcp1_get_link_encryption_status(struct mod_hdcp *hdcp, - enum mod_hdcp_encryption_status *encryption_status) -{ - *encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; - - if (mod_hdcp_hdcp1_link_maintenance(hdcp) != MOD_HDCP_STATUS_SUCCESS) - return MOD_HDCP_STATUS_FAILURE; - - *encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON; - - return MOD_HDCP_STATUS_SUCCESS; -} - enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp) { struct psp_context *psp = hdcp->config.psp.handle; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h index 1a663dbbf810..2937b4b61461 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h @@ -44,7 +44,8 @@ enum bgd_security_hdcp2_content_type { enum ta_dtm_command { TA_DTM_COMMAND__UNUSED_1 = 1, TA_DTM_COMMAND__TOPOLOGY_UPDATE_V2, - TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE + TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE, + TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3 }; /* DTM related enumerations */ @@ -86,6 +87,32 @@ struct ta_dtm_topology_update_input_v2 { uint32_t max_hdcp_supported_version; }; +/* For security reason/HW may change value, these encoder type enum values are not HW register values */ +/* Security code will check real HW register values and these SW enum values */ +enum ta_dtm_encoder_type { + TA_DTM_ENCODER_TYPE__INVALID = 0, + TA_DTM_ENCODER_TYPE__DIG = 0x10 +}; + +struct ta_dtm_topology_update_input_v3 { + /* display handle is unique across the driver and is used to identify a display */ + /* for all security interfaces which reference displays such as HDCP */ + /* link_hdcp_cap means link is HDCP-capable for audio HDCP capable property(informational), not for other logic(e.g. Crossbar) */ + uint32_t display_handle; + uint32_t is_active; + uint32_t is_miracast; + uint32_t controller; + uint32_t ddc_line; + uint32_t link_enc; + uint32_t stream_enc; + uint32_t dp_mst_vcid; + uint32_t is_assr; + uint32_t max_hdcp_supported_version; + enum ta_dtm_encoder_type encoder_type; + uint32_t phy_id; + uint32_t link_hdcp_cap; +}; + struct ta_dtm_topology_assr_enable { uint32_t display_topology_dig_be_index; }; @@ -99,6 +126,7 @@ struct ta_dtm_topology_assr_enable { union ta_dtm_cmd_input { struct ta_dtm_topology_update_input_v2 topology_update_v2; struct ta_dtm_topology_assr_enable topology_assr_enable; + struct ta_dtm_topology_update_input_v3 topology_update_v3; }; union ta_dtm_cmd_output { @@ -278,7 +306,8 @@ enum ta_hdcp2_version { TA_HDCP2_VERSION_UNKNOWN = 0, TA_HDCP2_VERSION_2_0 = 20, TA_HDCP2_VERSION_2_1 = 21, - TA_HDCP2_VERSION_2_2 = 22 + TA_HDCP2_VERSION_2_2 = 22, + TA_HDCP2_VERSION_2_3 = 23, }; /* input/output structures for HDCP commands */ diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h index acbeada5215b..c590493fd293 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h @@ -1,5 +1,5 @@ /* - * Copyright 2019 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -97,6 +97,7 @@ enum mod_hdcp_status { MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST, MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE, MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE, + MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE, }; struct mod_hdcp_displayport { @@ -120,6 +121,11 @@ enum mod_hdcp_display_state { MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED }; +struct mod_hdcp_psp_caps { + uint8_t dtm_v3_supported; + uint8_t opm_state_query_supported; +}; + enum mod_hdcp_display_disable_option { MOD_HDCP_DISPLAY_NOT_DISABLE = 0, MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION, @@ -152,6 +158,7 @@ struct mod_hdcp_ddc { struct mod_hdcp_psp { void *handle; void *funcs; + struct mod_hdcp_psp_caps caps; }; struct mod_hdcp_display_adjustment { @@ -227,6 +234,7 @@ struct mod_hdcp_display { uint8_t index; uint8_t controller; uint8_t dig_fe; + uint8_t stream_enc_idx; union { uint8_t vc_id; }; @@ -239,6 +247,9 @@ struct mod_hdcp_link { enum mod_hdcp_operation_mode mode; uint8_t dig_be; uint8_t ddc_line; + uint8_t link_enc_idx; + uint8_t phy_idx; + uint8_t hdcp_supported_informational; union { struct mod_hdcp_displayport dp; struct mod_hdcp_hdmi hdmi; diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 6270ecbd2438..2b00f334e93d 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -87,19 +87,19 @@ struct abm_parameters { }; static const struct abm_parameters abm_settings_config0[abm_defines_max_level] = { -// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blStart blRed - {0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xe0, 0xCCCC, 0xCCCC}, - {0xde, 0x85, 0x20, 0x00, 0xff, 0x90, 0xa8, 0x40, 0xdf, 0xCCCC, 0xCCCC}, - {0xb0, 0x50, 0x20, 0x00, 0xc0, 0x88, 0x78, 0x70, 0xa0, 0xCCCC, 0xCCCC}, - {0x82, 0x40, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, +// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart + {0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xe0, 0xf777, 0xcccc}, + {0xde, 0x85, 0x20, 0x00, 0xe0, 0x90, 0xa8, 0x40, 0xc8, 0xf777, 0xcccc}, + {0xb0, 0x50, 0x20, 0x00, 0xc0, 0x88, 0x78, 0x70, 0xa0, 0xeeee, 0x9999}, + {0x82, 0x40, 0x20, 0x00, 0x00, 0xb8, 0xb3, 0x70, 0x70, 0xe333, 0xb333}, }; static const struct abm_parameters abm_settings_config1[abm_defines_max_level] = { -// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blStart blRed - {0xf0, 0xd9, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, - {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, - {0x99, 0x65, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, - {0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, +// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart + {0xf0, 0xd9, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc}, + {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc}, + {0x99, 0x65, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc}, }; static const struct abm_parameters * const abm_settings[] = { @@ -660,7 +660,8 @@ static void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram } bool dmub_init_abm_config(struct resource_pool *res_pool, - struct dmcu_iram_parameters params) + struct dmcu_iram_parameters params, + unsigned int inst) { struct iram_table_v_2_2 ram_table; struct abm_config_table config; @@ -669,7 +670,7 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, uint32_t i, j = 0; #if defined(CONFIG_DRM_AMD_DC_DCN) - if (res_pool->abm == NULL && res_pool->multiple_abms[0] == NULL) + if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL) return false; #else if (res_pool->abm == NULL) @@ -728,13 +729,13 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, config.min_abm_backlight = ram_table.min_abm_backlight; #if defined(CONFIG_DRM_AMD_DC_DCN) - if (res_pool->multiple_abms[0]) - result = res_pool->multiple_abms[0]->funcs->init_abm_config( - res_pool->multiple_abms[0], (char *)(&config), sizeof(struct abm_config_table)); - else + if (res_pool->multiple_abms[inst]) { + result = res_pool->multiple_abms[inst]->funcs->init_abm_config( + res_pool->multiple_abms[inst], (char *)(&config), sizeof(struct abm_config_table), inst); + } else #endif result = res_pool->abm->funcs->init_abm_config( - res_pool->abm, (char *)(&config), sizeof(struct abm_config_table)); + res_pool->abm, (char *)(&config), sizeof(struct abm_config_table), 0); return result; } diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index 6f2eecce6baa..2a9f8e2d8080 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -49,6 +49,7 @@ struct dmcu_iram_parameters { bool dmcu_load_iram(struct dmcu *dmcu, struct dmcu_iram_parameters params); bool dmub_init_abm_config(struct resource_pool *res_pool, - struct dmcu_iram_parameters params); + struct dmcu_iram_parameters params, + unsigned int inst); #endif /* MODULES_POWER_POWER_HELPERS_H_ */ |