diff options
Diffstat (limited to 'drivers/gpu/drm/amd')
67 files changed, 1214 insertions, 424 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 08eced097bd8..2eb2c66843a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1276,7 +1276,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, r = drm_sched_job_add_dependency(&leader->base, fence); if (r) { dma_fence_put(fence); - goto error_cleanup; + return r; } } @@ -1303,7 +1303,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } if (r) { r = -EAGAIN; - goto error_unlock; + mutex_unlock(&p->adev->notifier_lock); + return r; } p->fence = dma_fence_get(&leader->base.s_fence->finished); @@ -1350,14 +1351,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, mutex_unlock(&p->adev->notifier_lock); mutex_unlock(&p->bo_list->bo_list_mutex); return 0; - -error_unlock: - mutex_unlock(&p->adev->notifier_lock); - -error_cleanup: - for (i = 0; i < p->gang_size; ++i) - drm_sched_job_cleanup(&p->jobs[i]->base); - return r; } /* Cleanup the parser structure */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6f715fb930bb..aa46726dfdb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4482,7 +4482,11 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) dev_info(adev->dev, "recover vram bo from shadow start\n"); mutex_lock(&adev->shadow_list_lock); list_for_each_entry(vmbo, &adev->shadow_list, shadow_list) { - shadow = &vmbo->bo; + /* If vm is compute context or adev is APU, shadow will be NULL */ + if (!vmbo->shadow) + continue; + shadow = vmbo->shadow; + /* No need to recover an evicted BO */ if (shadow->tbo.resource->mem_type != TTM_PL_TT || shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET || diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 35ed46b9249c..8a0a4464ea83 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -686,9 +686,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r if (r) return r; - r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); - if (r) - goto late_fini; + if (adev->gfx.cp_ecc_error_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (r) + goto late_fini; + } } else { amdgpu_ras_feature_enable_on_boot(adev, ras_block, 0); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index e9b45089a28a..863b2a34b2d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -38,6 +38,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, { struct fd f = fdget(fd); struct amdgpu_fpriv *fpriv; + struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; uint32_t id; int r; @@ -51,8 +52,11 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, return r; } - idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) + mgr = &fpriv->ctx_mgr; + mutex_lock(&mgr->lock); + idr_for_each_entry(&mgr->ctx_handles, ctx, id) amdgpu_ctx_priority_override(ctx, priority); + mutex_unlock(&mgr->lock); fdput(f); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index ecf8ceb53311..7609d206012f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -1313,13 +1313,6 @@ static int gfx_v11_0_sw_init(void *handle) if (r) return r; - /* ECC error */ - r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_ECC_ERROR, - &adev->gfx.cp_ecc_error_irq); - if (r) - return r; - /* FED error */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT, @@ -4442,7 +4435,6 @@ static int gfx_v11_0_hw_fini(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -5882,36 +5874,6 @@ static void gfx_v11_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev } } -#define CP_ME1_PIPE_INST_ADDR_INTERVAL 0x1 -#define SET_ECC_ME_PIPE_STATE(reg_addr, state) \ - do { \ - uint32_t tmp = RREG32_SOC15_IP(GC, reg_addr); \ - tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, state); \ - WREG32_SOC15_IP(GC, reg_addr, tmp); \ - } while (0) - -static int gfx_v11_0_set_cp_ecc_error_state(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - unsigned type, - enum amdgpu_interrupt_state state) -{ - uint32_t ecc_irq_state = 0; - uint32_t pipe0_int_cntl_addr = 0; - int i = 0; - - ecc_irq_state = (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0; - - pipe0_int_cntl_addr = SOC15_REG_OFFSET(GC, 0, regCP_ME1_PIPE0_INT_CNTL); - - WREG32_FIELD15_PREREG(GC, 0, CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, ecc_irq_state); - - for (i = 0; i < adev->gfx.mec.num_pipe_per_mec; i++) - SET_ECC_ME_PIPE_STATE(pipe0_int_cntl_addr + i * CP_ME1_PIPE_INST_ADDR_INTERVAL, - ecc_irq_state); - - return 0; -} - static int gfx_v11_0_set_eop_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, @@ -6329,11 +6291,6 @@ static const struct amdgpu_irq_src_funcs gfx_v11_0_priv_inst_irq_funcs = { .process = gfx_v11_0_priv_inst_irq, }; -static const struct amdgpu_irq_src_funcs gfx_v11_0_cp_ecc_error_irq_funcs = { - .set = gfx_v11_0_set_cp_ecc_error_state, - .process = amdgpu_gfx_cp_ecc_error_irq, -}; - static const struct amdgpu_irq_src_funcs gfx_v11_0_rlc_gc_fed_irq_funcs = { .process = gfx_v11_0_rlc_gc_fed_irq, }; @@ -6349,9 +6306,6 @@ static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.priv_inst_irq.num_types = 1; adev->gfx.priv_inst_irq.funcs = &gfx_v11_0_priv_inst_irq_funcs; - adev->gfx.cp_ecc_error_irq.num_types = 1; /* CP ECC error */ - adev->gfx.cp_ecc_error_irq.funcs = &gfx_v11_0_cp_ecc_error_irq_funcs; - adev->gfx.rlc_gc_fed_irq.num_types = 1; /* 0x80 FED error */ adev->gfx.rlc_gc_fed_irq.funcs = &gfx_v11_0_rlc_gc_fed_irq_funcs; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index ae09fc1cfe6b..c54d05bdc2d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3751,7 +3751,8 @@ static int gfx_v9_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) + amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index ab2556ca984e..be16e627e54b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -1161,7 +1161,6 @@ static int gmc_v10_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index af7b3ba1ca00..abdb8d8421b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -954,7 +954,6 @@ static int gmc_v11_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v11_0_gart_disable(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index b06170c00dfc..83d22dd8b871 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1987,7 +1987,6 @@ static int gmc_v9_0_hw_fini(void *handle) if (adev->mmhub.funcs->update_power_gating) adev->mmhub.funcs->update_power_gating(adev, false); - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index a1b751d9ac06..323d68b2124f 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -54,6 +54,7 @@ static int jpeg_v3_0_early_init(void *handle) switch (adev->ip_versions[UVD_HWIP][0]) { case IP_VERSION(3, 1, 1): + case IP_VERSION(3, 1, 2): break; default: harvest = RREG32_SOC15(JPEG, 0, mmCC_UVD_HARVESTING); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index b5affba22156..8b8ddf050266 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1903,9 +1903,11 @@ static int sdma_v4_0_hw_fini(void *handle) return 0; } - for (i = 0; i < adev->sdma.num_instances; i++) { - amdgpu_irq_put(adev, &adev->sdma.ecc_irq, - AMDGPU_SDMA_IRQ_INSTANCE0 + i); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + amdgpu_irq_put(adev, &adev->sdma.ecc_irq, + AMDGPU_SDMA_IRQ_INSTANCE0 + i); + } } sdma_v4_0_ctx_switch_enable(adev, false); diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index c82b3a7ea5f0..20cf861bfda1 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -778,7 +778,7 @@ static int soc21_common_early_init(void *handle) AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_JPEG; - adev->external_rev_id = adev->rev_id + 0x1; + adev->external_rev_id = adev->rev_id + 0x80; break; default: 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 62af874f26e0..f54d670ab3ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2274,7 +2274,7 @@ static int dm_late_init(void *handle) struct dc_link *edp_links[MAX_NUM_EDP]; int edp_num; - get_edp_links(adev->dm.dc, edp_links, &edp_num); + dc_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; @@ -7876,6 +7876,13 @@ static void amdgpu_dm_commit_cursors(struct drm_atomic_state *state) handle_cursor_update(plane, old_plane_state); } +static inline uint32_t get_mem_type(struct drm_framebuffer *fb) +{ + struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]); + + return abo->tbo.resource ? abo->tbo.resource->mem_type : 0; +} + static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dc_state *dc_state, struct drm_device *dev, @@ -7950,6 +7957,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, continue; dc_plane = dm_new_plane_state->dc_state; + if (!dc_plane) + continue; bundle->surface_updates[planes_count].surface = dc_plane; if (new_pcrtc_state->color_mgmt_changed) { @@ -8016,11 +8025,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, /* * Only allow immediate flips for fast updates that don't - * change FB pitch, DCC state, rotation or mirroing. + * change memory domain, FB pitch, DCC state, rotation or + * mirroring. */ bundle->flip_addrs[planes_count].flip_immediate = crtc->state->async_flip && - acrtc_state->update_type == UPDATE_TYPE_FAST; + acrtc_state->update_type == UPDATE_TYPE_FAST && + get_mem_type(old_plane_state->fb) == get_mem_type(fb); timestamp_ns = ktime_get_ns(); bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); @@ -8533,6 +8544,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i); if (!connector) @@ -8581,6 +8595,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + new_crtc_state = NULL; old_crtc_state = NULL; @@ -9601,8 +9618,9 @@ static int dm_update_plane_state(struct dc *dc, return -EINVAL; } + if (dm_old_plane_state->dc_state) + dc_plane_state_release(dm_old_plane_state->dc_state); - dc_plane_state_release(dm_old_plane_state->dc_state); dm_new_plane_state->dc_state = NULL; *lock_and_validation_needed = true; @@ -10150,6 +10168,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); if (ret) { DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto fail; } 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 09a3efa517da..4a5dae578d97 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 @@ -724,7 +724,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us for (i = 0; i < (unsigned int)(link_training_settings.link_settings.lane_count); i++) link_training_settings.hw_lane_settings[i] = link->cur_lane_setting[i]; - dc_link_set_test_pattern( + dc_link_dp_set_test_pattern( link, test_pattern, DP_TEST_PATTERN_COLOR_SPACE_RGB, 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 8dc442f90eaf..3da519957f6c 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 @@ -385,13 +385,17 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (aconnector->dc_sink && connector->state) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); - struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; - struct hdcp_workqueue *hdcp_w = &hdcp_work[aconnector->dc_link->link_index]; - connector->state->hdcp_content_type = - hdcp_w->hdcp_content_type[connector->index]; - connector->state->content_protection = - hdcp_w->content_protection[connector->index]; + if (adev->dm.hdcp_workqueue) { + struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; + struct hdcp_workqueue *hdcp_w = + &hdcp_work[aconnector->dc_link->link_index]; + + connector->state->hdcp_content_type = + hdcp_w->hdcp_content_type[connector->index]; + connector->state->content_protection = + hdcp_w->content_protection[connector->index]; + } } #endif @@ -1410,6 +1414,7 @@ int pre_validate_dsc(struct drm_atomic_state *state, ret = pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars); if (ret != 0) { DRM_INFO_ONCE("pre_compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto clean_exit; } 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 69691daf4dbb..73a45ec27f90 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 @@ -104,7 +104,7 @@ void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_m int edp_num; unsigned int panel_inst; - get_edp_links(dc, edp_links, &edp_num); + dc_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); @@ -129,7 +129,7 @@ void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr) int edp_num; unsigned int panel_inst; - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num) { for (panel_inst = 0; panel_inst < edp_num; panel_inst++) { edp_link = edp_links[panel_inst]; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index 61768bf726f8..31ee81ebb4ea 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -805,6 +805,8 @@ void dcn32_clk_mgr_construct( struct pp_smu_funcs *pp_smu, struct dccg *dccg) { + struct clk_log_info log_info = {0}; + clk_mgr->base.ctx = ctx; clk_mgr->base.funcs = &dcn32_funcs; if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) { @@ -838,6 +840,7 @@ void dcn32_clk_mgr_construct( clk_mgr->base.clks.ref_dtbclk_khz = 268750; } + /* integer part is now VCO frequency in kHz */ clk_mgr->base.dentist_vco_freq_khz = dcn32_get_vco_frequency_from_reg(clk_mgr); @@ -845,6 +848,8 @@ void dcn32_clk_mgr_construct( if (clk_mgr->base.dentist_vco_freq_khz == 0) clk_mgr->base.dentist_vco_freq_khz = 4300000; /* Updated as per HW docs */ + dcn32_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); + if (ctx->dc->debug.disable_dtb_ref_clk_switch && clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) { clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 1c218c526650..d406d7b74c6c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -53,7 +53,6 @@ #include "link_encoder.h" #include "link_enc_cfg.h" -#include "dc_link.h" #include "link.h" #include "dm_helpers.h" #include "mem_input.h" @@ -1298,7 +1297,7 @@ static void detect_edp_presence(struct dc *dc) int i; int edp_num; - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (!edp_num) return; @@ -4317,157 +4316,6 @@ bool dc_is_dmcu_initialized(struct dc *dc) return false; } -bool dc_is_oem_i2c_device_present( - struct dc *dc, - size_t slave_address) -{ - if (dc->res_pool->oem_device) - return dce_i2c_oem_device_present( - dc->res_pool, - dc->res_pool->oem_device, - slave_address); - - return false; -} - -bool dc_submit_i2c( - struct dc *dc, - uint32_t link_index, - struct i2c_command *cmd) -{ - - struct dc_link *link = dc->links[link_index]; - struct ddc_service *ddc = link->ddc; - return dce_i2c_submit_command( - dc->res_pool, - ddc->ddc_pin, - cmd); -} - -bool dc_submit_i2c_oem( - struct dc *dc, - struct i2c_command *cmd) -{ - struct ddc_service *ddc = dc->res_pool->oem_device; - if (ddc) - return dce_i2c_submit_command( - dc->res_pool, - ddc->ddc_pin, - cmd); - - return false; -} - -static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) -{ - if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { - BREAK_TO_DEBUGGER(); - return false; - } - - dc_sink_retain(sink); - - dc_link->remote_sinks[dc_link->sink_count] = sink; - dc_link->sink_count++; - - return true; -} - -/* - * dc_link_add_remote_sink() - Create a sink and attach it to an existing link - * - * EDID length is in bytes - */ -struct dc_sink *dc_link_add_remote_sink( - struct dc_link *link, - const uint8_t *edid, - int len, - struct dc_sink_init_data *init_data) -{ - struct dc_sink *dc_sink; - enum dc_edid_status edid_status; - - if (len > DC_MAX_EDID_BUFFER_SIZE) { - dm_error("Max EDID buffer size breached!\n"); - return NULL; - } - - if (!init_data) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - if (!init_data->link) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dc_sink = dc_sink_create(init_data); - - if (!dc_sink) - return NULL; - - memmove(dc_sink->dc_edid.raw_edid, edid, len); - dc_sink->dc_edid.length = len; - - if (!link_add_remote_sink_helper( - link, - dc_sink)) - goto fail_add_sink; - - edid_status = dm_helpers_parse_edid_caps( - link, - &dc_sink->dc_edid, - &dc_sink->edid_caps); - - /* - * Treat device as no EDID device if EDID - * parsing fails - */ - if (edid_status != EDID_OK && edid_status != EDID_PARTIAL_VALID) { - dc_sink->dc_edid.length = 0; - dm_error("Bad EDID, status%d!\n", edid_status); - } - - return dc_sink; - -fail_add_sink: - dc_sink_release(dc_sink); - return NULL; -} - -/* - * dc_link_remove_remote_sink() - Remove a remote sink from a dc_link - * - * Note that this just removes the struct dc_sink - it doesn't - * program hardware or alter other members of dc_link - */ -void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) -{ - int i; - - if (!link->sink_count) { - BREAK_TO_DEBUGGER(); - return; - } - - for (i = 0; i < link->sink_count; i++) { - if (link->remote_sinks[i] == sink) { - dc_sink_release(sink); - link->remote_sinks[i] = NULL; - - /* shrink array to remove empty place */ - while (i < link->sink_count - 1) { - link->remote_sinks[i] = link->remote_sinks[i+1]; - i++; - } - link->remote_sinks[i] = NULL; - link->sink_count--; - return; - } - } -} - void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info) { info->displayClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dispclk_khz; @@ -4990,7 +4838,7 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo return; } - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); /* Determine panel inst */ for (i = 0; i < edp_num; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index a951e10416ee..862cb0f93b7d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -34,6 +34,49 @@ * in this file which calls link functions. */ #include "link.h" +#include "dce/dce_i2c.h" +struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index) +{ + return dc->links[link_index]; +} + +void dc_get_edp_links(const struct dc *dc, + struct dc_link **edp_links, + int *edp_num) +{ + int i; + + *edp_num = 0; + for (i = 0; i < dc->link_count; i++) { + // report any eDP links, even unconnected DDI's + if (!dc->links[i]) + continue; + if (dc->links[i]->connector_signal == SIGNAL_TYPE_EDP) { + edp_links[*edp_num] = dc->links[i]; + if (++(*edp_num) == MAX_NUM_EDP) + return; + } + } +} + +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, i; + + *inst_out = 0; + if (link->connector_signal != SIGNAL_TYPE_EDP) + return false; + dc_get_edp_links(dc, edp_links, &edp_num); + for (i = 0; i < edp_num; i++) { + if (link == edp_links[i]) + break; + (*inst_out)++; + } + return true; +} bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) { @@ -101,3 +144,47 @@ bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx) { return link_update_dsc_config(pipe_ctx); } + +bool dc_is_oem_i2c_device_present( + struct dc *dc, + size_t slave_address) +{ + if (dc->res_pool->oem_device) + return dce_i2c_oem_device_present( + dc->res_pool, + dc->res_pool->oem_device, + slave_address); + + return false; +} + +bool dc_submit_i2c( + struct dc *dc, + uint32_t link_index, + struct i2c_command *cmd) +{ + + struct dc_link *link = dc->links[link_index]; + struct ddc_service *ddc = link->ddc; + + return dce_i2c_submit_command( + dc->res_pool, + ddc->ddc_pin, + cmd); +} + +bool dc_submit_i2c_oem( + struct dc *dc, + struct i2c_command *cmd) +{ + struct ddc_service *ddc = dc->res_pool->oem_device; + + if (ddc) + return dce_i2c_submit_command( + dc->res_pool, + ddc->ddc_pin, + cmd); + + return false; +} + 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 d9f2ef242b0f..0ae6dcc403a4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1707,6 +1707,9 @@ bool dc_remove_plane_from_context( struct dc_stream_status *stream_status = NULL; struct resource_pool *pool = dc->res_pool; + if (!plane_state) + return true; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { stream_status = &context->stream_status[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 1fde43378689..3fb868f2f6f5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -795,6 +795,7 @@ struct dc_debug_options { unsigned int force_odm_combine; //bit vector based on otg inst unsigned int seamless_boot_odm_combine; unsigned int force_odm_combine_4to1; //bit vector based on otg inst + int minimum_z8_residency_time; bool disable_z9_mpc; unsigned int force_fclk_khz; bool enable_tri_buf; @@ -1379,8 +1380,159 @@ struct dc_plane_state *dc_get_surface_for_mpcc(struct dc *dc, uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane); /* Link Interfaces */ -/* TODO: remove this after resolving external dependencies */ -#include "dc_link.h" +/* + * A link contains one or more sinks and their connected status. + * The currently active signal type (HDMI, DP-SST, DP-MST) is also reported. + */ +struct dc_link { + struct dc_sink *remote_sinks[MAX_SINKS_PER_LINK]; + unsigned int sink_count; + struct dc_sink *local_sink; + unsigned int link_index; + enum dc_connection_type type; + enum signal_type connector_signal; + enum dc_irq_source irq_source_hpd; + enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */ + + bool is_hpd_filter_disabled; + bool dp_ss_off; + + /** + * @link_state_valid: + * + * If there is no link and local sink, this variable should be set to + * false. Otherwise, it should be set to true; usually, the function + * core_link_enable_stream sets this field to true. + */ + bool link_state_valid; + bool aux_access_disabled; + bool sync_lt_in_progress; + bool skip_stream_reenable; + bool is_internal_display; + /** @todo Rename. Flag an endpoint as having a programmable mapping to a DIG encoder. */ + bool is_dig_mapping_flexible; + bool hpd_status; /* HPD status of link without physical HPD pin. */ + bool is_hpd_pending; /* Indicates a new received hpd */ + bool is_automated; /* Indicates automated testing */ + + bool edp_sink_present; + + struct dp_trace dp_trace; + + /* caps is the same as reported_link_cap. link_traing use + * reported_link_cap. Will clean up. TODO + */ + struct dc_link_settings reported_link_cap; + struct dc_link_settings verified_link_cap; + struct dc_link_settings cur_link_settings; + struct dc_lane_settings cur_lane_setting[LANE_COUNT_DP_MAX]; + struct dc_link_settings preferred_link_setting; + /* preferred_training_settings are override values that + * come from DM. DM is responsible for the memory + * management of the override pointers. + */ + struct dc_link_training_overrides preferred_training_settings; + struct dp_audio_test_data audio_test_data; + + uint8_t ddc_hw_inst; + + uint8_t hpd_src; + + uint8_t link_enc_hw_inst; + /* DIG link encoder ID. Used as index in link encoder resource pool. + * For links with fixed mapping to DIG, this is not changed after dc_link + * object creation. + */ + enum engine_id eng_id; + + bool test_pattern_enabled; + union compliance_test_state compliance_test_state; + + void *priv; + + struct ddc_service *ddc; + + bool aux_mode; + + /* Private to DC core */ + + const struct dc *dc; + + struct dc_context *ctx; + + struct panel_cntl *panel_cntl; + struct link_encoder *link_enc; + struct graphics_object_id link_id; + /* Endpoint type distinguishes display endpoints which do not have entries + * in the BIOS connector table from those that do. Helps when tracking link + * encoder to display endpoint assignments. + */ + enum display_endpoint_type ep_type; + union ddi_channel_mapping ddi_channel_mapping; + struct connector_device_tag_info device_tag; + struct dpcd_caps dpcd_caps; + uint32_t dongle_max_pix_clk; + unsigned short chip_caps; + unsigned int dpcd_sink_count; +#if defined(CONFIG_DRM_AMD_DC_HDCP) + struct hdcp_caps hdcp_caps; +#endif + enum edp_revision edp_revision; + union dpcd_sink_ext_caps dpcd_sink_ext_caps; + + struct psr_settings psr_settings; + + /* Drive settings read from integrated info table */ + struct dc_lane_settings bios_forced_drive_settings; + + /* Vendor specific LTTPR workaround variables */ + uint8_t vendor_specific_lttpr_link_rate_wa; + bool apply_vendor_specific_lttpr_link_rate_wa; + + /* MST record stream using this link */ + struct link_flags { + bool dp_keep_receiver_powered; + bool dp_skip_DID2; + bool dp_skip_reset_segment; + bool dp_skip_fs_144hz; + bool dp_mot_reset_segment; + /* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */ + bool dpia_mst_dsc_always_on; + /* Forced DPIA into TBT3 compatibility mode. */ + bool dpia_forced_tbt3_mode; + bool dongle_mode_timing_override; + } wa_flags; + struct link_mst_stream_allocation_table mst_stream_alloc_table; + + struct dc_link_status link_status; + struct dprx_states dprx_states; + + struct gpio *hpd_gpio; + enum dc_link_fec_state fec_state; + bool link_powered_externally; // Used to bypass hardware sequencing delays when panel is powered down forcibly + + struct dc_panel_config panel_config; + struct phy_state phy_state; + // BW ALLOCATON USB4 ONLY + struct dc_dpia_bw_alloc dpia_bw_alloc_config; +}; + +/* Return an enumerated dc_link. + * dc_link order is constant and determined at + * boot time. They cannot be created or destroyed. + * Use dc_get_caps() to get number of links. + */ +struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index); + +/* Return instance id of the edp link. Inst 0 is primary edp link. */ +bool dc_get_edp_link_panel_inst(const struct dc *dc, + const struct dc_link *link, + unsigned int *inst_out); + +/* Return an array of link pointers to edp links. */ +void dc_get_edp_links(const struct dc *dc, + struct dc_link **edp_links, + int *edp_num); /* The function initiates detection handshake over the given link. It first * determines if there are display connections over the link. If so it initiates @@ -1404,6 +1556,38 @@ uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane); */ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason); +struct dc_sink_init_data; + +/* When link connection type is dc_connection_mst_branch, remote sink can be + * added to the link. The interface creates a remote sink and associates it with + * current link. The sink will be retained by link until remove remote sink is + * called. + * + * @dc_link - link the remote sink will be added to. + * @edid - byte array of EDID raw data. + * @len - size of the edid in byte + * @init_data - + */ +struct dc_sink *dc_link_add_remote_sink( + struct dc_link *dc_link, + const uint8_t *edid, + int len, + struct dc_sink_init_data *init_data); + +/* Remove remote sink from a link with dc_connection_mst_branch connection type. + * @link - link the sink should be removed from + * @sink - sink to be removed. + */ +void dc_link_remove_remote_sink( + struct dc_link *link, + struct dc_sink *sink); + +/* Enable HPD interrupt handler for a given link */ +void dc_link_enable_hpd(const struct dc_link *link); + +/* Disable HPD interrupt handler for a given link */ +void dc_link_disable_hpd(const struct dc_link *link); + /* determine if there is a sink connected to the link * * @type - dc_connection_single if connected, dc_connection_none otherwise. @@ -1417,15 +1601,119 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason); bool dc_link_detect_connection_type(struct dc_link *link, enum dc_connection_type *type); +/* query current hpd pin value + * return - true HPD is asserted (HPD high), false otherwise (HPD low) + * + */ +bool dc_link_get_hpd_state(struct dc_link *dc_link); + /* Getter for cached link status from given link */ const struct dc_link_status *dc_link_get_status(const struct dc_link *link); +/* enable/disable hardware HPD filter. + * + * @link - The link the HPD pin is associated with. + * @enable = true - enable hardware HPD filter. HPD event will only queued to irq + * handler once after no HPD change has been detected within dc default HPD + * filtering interval since last HPD event. i.e if display keeps toggling hpd + * pulses within default HPD interval, no HPD event will be received until HPD + * toggles have stopped. Then HPD event will be queued to irq handler once after + * dc default HPD filtering interval since last HPD event. + * + * @enable = false - disable hardware HPD filter. HPD event will be queued + * immediately to irq handler after no HPD change has been detected within + * IRQ_HPD (aka HPD short pulse) interval (i.e 2ms). + */ +void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); + +/* submit i2c read/write payloads through ddc channel + * @link_index - index to a link with ddc in i2c mode + * @cmd - i2c command structure + * return - true if success, false otherwise. + */ +bool dc_submit_i2c( + struct dc *dc, + uint32_t link_index, + struct i2c_command *cmd); + +/* submit i2c read/write payloads through oem channel + * @link_index - index to a link with ddc in i2c mode + * @cmd - i2c command structure + * return - true if success, false otherwise. + */ +bool dc_submit_i2c_oem( + struct dc *dc, + struct i2c_command *cmd); + +enum aux_return_code_type; +/* Attempt to transfer the given aux payload. This function does not perform + * retries or handle error states. The reply is returned in the payload->reply + * and the result through operation_result. Returns the number of bytes + * transferred,or -1 on a failure. + */ +int dc_link_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *payload, + enum aux_return_code_type *operation_result); + +bool dc_is_oem_i2c_device_present( + struct dc *dc, + size_t slave_address +); + #ifdef CONFIG_DRM_AMD_DC_HDCP + /* return true if the connected receiver supports the hdcp version */ bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal); bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal); #endif +/* Notify DC about DP RX Interrupt (aka DP IRQ_HPD). + * + * TODO - When defer_handling is true the function will have a different purpose. + * It no longer does complete hpd rx irq handling. We should create a separate + * interface specifically for this case. + * + * Return: + * true - Downstream port status changed. DM should call DC to do the + * detection. + * false - no change in Downstream port status. No further action required + * from DM. + */ +bool dc_link_handle_hpd_rx_irq(struct dc_link *dc_link, + union hpd_irq_data *hpd_irq_dpcd_data, bool *out_link_loss, + bool defer_handling, bool *has_left_work); +/* handle DP specs define test automation sequence*/ +void dc_link_dp_handle_automated_test(struct dc_link *link); + +/* handle DP Link loss sequence and try to recover RX link loss with best + * effort + */ +void dc_link_dp_handle_link_loss(struct dc_link *link); + +/* Determine if hpd rx irq should be handled or ignored + * return true - hpd rx irq should be handled. + * return false - it is safe to ignore hpd rx irq event + */ +bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link); + +/* Determine if link loss is indicated with a given hpd_irq_dpcd_data. + * @link - link the hpd irq data associated with + * @hpd_irq_dpcd_data - input hpd irq data + * return - true if hpd irq data indicates a link lost + */ +bool dc_link_check_link_loss_status(struct dc_link *link, + union hpd_irq_data *hpd_irq_dpcd_data); + +/* Read hpd rx irq data from a given link + * @link - link where the hpd irq data should be read from + * @irq_data - output hpd irq data + * return - DC_OK if hpd irq data is read successfully, otherwise hpd irq data + * read has failed. + */ +enum dc_status dc_link_dp_read_hpd_rx_irq_data( + struct dc_link *link, + union hpd_irq_data *irq_data); + /* The function clears recorded DP RX states in the link. DM should call this * function when it is resuming from S3 power state to previously connected links. * @@ -1493,6 +1781,268 @@ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map); * interface i.e stream_update->dsc_config */ bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx); + +/* translate a raw link rate data to bandwidth in kbps */ +uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw); + +/* determine the optimal bandwidth given link and required bw. + * @link - current detected link + * @req_bw - requested bandwidth in kbps + * @link_settings - returned most optimal link settings that can fit the + * requested bandwidth + * return - false if link can't support requested bandwidth, true if link + * settings is found. + */ +bool dc_link_decide_edp_link_settings(struct dc_link *link, + struct dc_link_settings *link_settings, + uint32_t req_bw); + +/* return the max dp link settings can be driven by the link without considering + * connected RX device and its capability + */ +bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, + struct dc_link_settings *max_link_enc_cap); + +/* determine when the link is driving MST mode, what DP link channel coding + * format will be used. The decision will remain unchanged until next HPD event. + * + * @link - a link with DP RX connection + * return - if stream is committed to this link with MST signal type, type of + * channel coding format dc will choose. + */ +enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format( + const struct dc_link *link); + +/* get max dp link settings the link can enable with all things considered. (i.e + * TX/RX/Cable capabilities and dp override policies. + * + * @link - a link with DP RX connection + * return - max dp link settings the link can enable. + * + */ +const struct dc_link_settings *dc_link_get_link_cap(const struct dc_link *link); + +/* Check if a RX (ex. DP sink, MST hub, passive or active dongle) is connected + * to a link with dp connector signal type. + * @link - a link with dp connector signal type + * return - true if connected, false otherwise + */ +bool dc_link_is_dp_sink_present(struct dc_link *link); + +/* Force DP lane settings update to main-link video signal and notify the change + * to DP RX via DPCD. This is a debug interface used for video signal integrity + * tuning purpose. The interface assumes link has already been enabled with DP + * signal. + * + * @lt_settings - a container structure with desired hw_lane_settings + */ +void dc_link_set_drive_settings(struct dc *dc, + struct link_training_settings *lt_settings, + const struct dc_link *link); + +/* Enable a test pattern in Link or PHY layer in an active link for compliance + * test or debugging purpose. The test pattern will remain until next un-plug. + * + * @link - active link with DP signal output enabled. + * @test_pattern - desired test pattern to output. + * NOTE: set to DP_TEST_PATTERN_VIDEO_MODE to disable previous test pattern. + * @test_pattern_color_space - for video test pattern choose a desired color + * space. + * @p_link_settings - For PHY pattern choose a desired link settings + * @p_custom_pattern - some test pattern will require a custom input to + * customize some pattern details. Otherwise keep it to NULL. + * @cust_pattern_size - size of the custom pattern input. + * + */ +bool dc_link_dp_set_test_pattern( + struct dc_link *link, + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size); + +/* Force DP link settings to always use a specific value until reboot to a + * specific link. If link has already been enabled, the interface will also + * switch to desired link settings immediately. This is a debug interface to + * generic dp issue trouble shooting. + */ +void dc_link_set_preferred_link_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link *link); + +/* Force DP link to customize a specific link training behavior by overriding to + * standard DP specs defined protocol. This is a debug interface to trouble shoot + * display specific link training issues or apply some display specific + * workaround in link training. + * + * @link_settings - if not NULL, force preferred link settings to the link. + * @lt_override - a set of override pointers. If any pointer is none NULL, dc + * will apply this particular override in future link training. If NULL is + * passed in, dc resets previous overrides. + * NOTE: DM must keep the memory from override pointers until DM resets preferred + * training settings. + */ +void dc_link_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain); + +/* return - true if FEC is supported with connected DP RX, false otherwise */ +bool dc_link_is_fec_supported(const struct dc_link *link); + +/* query FEC enablement policy to determine if FEC will be enabled by dc during + * link enablement. + * return - true if FEC should be enabled, false otherwise. + */ +bool dc_link_should_enable_fec(const struct dc_link *link); + +/* determine lttpr mode the current link should be enabled with a specific link + * settings. + */ +enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link, + struct dc_link_settings *link_setting); + +/* Force DP RX to update its power state. + * NOTE: this interface doesn't update dp main-link. Calling this function will + * cause DP TX main-link and DP RX power states out of sync. DM has to restore + * RX power state back upon finish DM specific execution requiring DP RX in a + * specific power state. + * @on - true to set DP RX in D0 power state, false to set DP RX in D3 power + * state. + */ +void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on); + +/* Force link to read base dp receiver caps from dpcd 000h - 00Fh and overwrite + * current value read from extended receiver cap from 02200h - 0220Fh. + * Some DP RX has problems of providing accurate DP receiver caps from extended + * field, this interface is a workaround to revert link back to use base caps. + */ +void dc_link_overwrite_extended_receiver_cap( + struct dc_link *link); + +void dc_link_edp_panel_backlight_power_on(struct dc_link *link, + bool wait_for_hpd); + +/* 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. + */ +bool dc_link_set_backlight_level(const struct dc_link *dc_link, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp); + +/* Set/get nits-based backlight level of an embedded panel (eDP, LVDS). */ +bool dc_link_set_backlight_level_nits(struct dc_link *link, + bool isHDR, + uint32_t backlight_millinits, + uint32_t transition_time_in_ms); + +bool dc_link_get_backlight_level_nits(struct dc_link *link, + uint32_t *backlight_millinits, + uint32_t *backlight_millinits_peak); + +int dc_link_get_backlight_level(const struct dc_link *dc_link); + +int dc_link_get_target_backlight_pwm(const struct dc_link *link); + +bool dc_link_set_psr_allow_active(struct dc_link *dc_link, const bool *enable, + bool wait, bool force_static, const unsigned int *power_opts); + +bool dc_link_get_psr_state(const struct dc_link *dc_link, enum dc_psr_state *state); + +bool dc_link_setup_psr(struct dc_link *dc_link, + const struct dc_stream_state *stream, struct psr_config *psr_config, + struct psr_context *psr_context); + +/* On eDP links this function call will stall until T12 has elapsed. + * If the panel is not in power off state, this function will return + * immediately. + */ +bool dc_link_wait_for_t12(struct dc_link *link); + +/* Determine if dp trace has been initialized to reflect upto date result * + * return - true if trace is initialized and has valid data. False dp trace + * doesn't have valid result. + */ +bool dc_dp_trace_is_initialized(struct dc_link *link); + +/* Query a dp trace flag to indicate if the current dp trace data has been + * logged before + */ +bool dc_dp_trace_is_logged(struct dc_link *link, + bool in_detection); + +/* Set dp trace flag to indicate whether DM has already logged the current dp + * trace data. DM can set is_logged to true upon logging and check + * dc_dp_trace_is_logged before logging to avoid logging the same result twice. + */ +void dc_dp_trace_set_is_logged_flag(struct dc_link *link, + bool in_detection, + bool is_logged); + +/* Obtain driver time stamp for last dp link training end. The time stamp is + * formatted based on dm_get_timestamp DM function. + * @in_detection - true to get link training end time stamp of last link + * training in detection sequence. false to get link training end time stamp + * of last link training in commit (dpms) sequence + */ +unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, + bool in_detection); + +/* Get how many link training attempts dc has done with latest sequence. + * @in_detection - true to get link training count of last link + * training in detection sequence. false to get link training count of last link + * training in commit (dpms) sequence + */ +struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link, + bool in_detection); + +/* Get how many link loss has happened since last link training attempts */ +unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link); + +/* + * USB4 DPIA BW ALLOCATION PUBLIC FUNCTIONS + */ +/* + * Send a request from DP-Tx requesting to allocate BW remotely after + * allocating it locally. This will get processed by CM and a CB function + * will be called. + * + * @link: pointer to the dc_link struct instance + * @req_bw: The requested bw in Kbyte to allocated + * + * return: none + */ +void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw); + +/* + * Handle function for when the status of the Request above is complete. + * We will find out the result of allocating on CM and update structs. + * + * @link: pointer to the dc_link struct instance + * @bw: Allocated or Estimated BW depending on the result + * @result: Response type + * + * return: none + */ +void dc_link_handle_usb4_bw_alloc_response(struct dc_link *link, + uint8_t bw, uint8_t result); + +/* + * Handle the USB4 BW Allocation related functionality here: + * Plug => Try to allocate max bw from timing parameters supported by the sink + * Unplug => de-allocate bw + * + * @link: pointer to the dc_link struct instance + * @peak_bw: Peak bw used by the link/sink + * + * return: allocated bw else return 0 + */ +int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link( + struct dc_link *link, int peak_bw); + /* Sink Interfaces - A sink corresponds to a display output device */ struct dc_container_id { diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 809a1851f196..4bccce94d83b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1261,4 +1261,111 @@ union dpcd_sink_ext_caps { } bits; uint8_t raw; }; + +enum dc_link_fec_state { + dc_link_fec_not_ready, + dc_link_fec_ready, + dc_link_fec_enabled +}; + +union dpcd_psr_configuration { + struct { + unsigned char ENABLE : 1; + unsigned char TRANSMITTER_ACTIVE_IN_PSR : 1; + unsigned char CRC_VERIFICATION : 1; + unsigned char FRAME_CAPTURE_INDICATION : 1; + /* For eDP 1.4, PSR v2*/ + unsigned char LINE_CAPTURE_INDICATION : 1; + /* For eDP 1.4, PSR v2*/ + unsigned char IRQ_HPD_WITH_CRC_ERROR : 1; + unsigned char ENABLE_PSR2 : 1; + unsigned char EARLY_TRANSPORT_ENABLE : 1; + } bits; + unsigned char raw; +}; + +union dpcd_alpm_configuration { + struct { + unsigned char ENABLE : 1; + unsigned char IRQ_HPD_ENABLE : 1; + unsigned char RESERVED : 6; + } bits; + unsigned char raw; +}; + +union dpcd_sink_active_vtotal_control_mode { + struct { + unsigned char ENABLE : 1; + unsigned char RESERVED : 7; + } bits; + unsigned char raw; +}; + +union psr_error_status { + struct { + unsigned char LINK_CRC_ERROR :1; + unsigned char RFB_STORAGE_ERROR :1; + unsigned char VSC_SDP_ERROR :1; + unsigned char RESERVED :5; + } bits; + unsigned char raw; +}; + +union psr_sink_psr_status { + struct { + unsigned char SINK_SELF_REFRESH_STATUS :3; + unsigned char RESERVED :5; + } bits; + unsigned char raw; +}; + +struct edp_trace_power_timestamps { + uint64_t poweroff; + uint64_t poweron; +}; + +struct dp_trace_lt_counts { + unsigned int total; + unsigned int fail; +}; + +enum link_training_result { + LINK_TRAINING_SUCCESS, + LINK_TRAINING_CR_FAIL_LANE0, + LINK_TRAINING_CR_FAIL_LANE1, + LINK_TRAINING_CR_FAIL_LANE23, + /* CR DONE bit is cleared during EQ step */ + LINK_TRAINING_EQ_FAIL_CR, + /* CR DONE bit is cleared but LANE0_CR_DONE is set during EQ step */ + LINK_TRAINING_EQ_FAIL_CR_PARTIAL, + /* other failure during EQ step */ + LINK_TRAINING_EQ_FAIL_EQ, + LINK_TRAINING_LQA_FAIL, + /* one of the CR,EQ or symbol lock is dropped */ + LINK_TRAINING_LINK_LOSS, + /* Abort link training (because sink unplugged) */ + LINK_TRAINING_ABORT, + DP_128b_132b_LT_FAILED, + DP_128b_132b_MAX_LOOP_COUNT_REACHED, + DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT, + DP_128b_132b_CDS_DONE_TIMEOUT, +}; + +struct dp_trace_lt { + struct dp_trace_lt_counts counts; + struct dp_trace_timestamps { + unsigned long long start; + unsigned long long end; + } timestamps; + enum link_training_result result; + bool is_logged; +}; + +struct dp_trace { + struct dp_trace_lt detect_lt_trace; + struct dp_trace_lt commit_lt_trace; + unsigned int link_loss_count; + bool is_initialized; + struct edp_trace_power_timestamps edp_trace_power_timestamps; +}; #endif /* DC_DP_TYPES_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 cc3d6fb39364..a583a72845fe 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -1085,5 +1085,19 @@ struct tg_color { uint16_t color_b_cb; }; +enum symclk_state { + SYMCLK_OFF_TX_OFF, + SYMCLK_ON_TX_ON, + SYMCLK_ON_TX_OFF, +}; + +struct phy_state { + struct { + uint8_t otg : 1; + uint8_t reserved : 7; + } symclk_ref_cnts; + enum symclk_state symclk_state; +}; + #endif /* DC_HW_TYPES_H */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 27d0242d6cbd..cba65766ef47 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -38,6 +38,7 @@ #include "dc_hw_types.h" #include "dal_types.h" #include "grph_object_defs.h" +#include "grph_object_ctrl_defs.h" #ifdef CONFIG_DRM_AMD_DC_HDCP #include "dm_cp_psp.h" @@ -982,4 +983,114 @@ struct hdcp_caps { union hdcp_bcaps bcaps; }; #endif + +/* DP MST stream allocation (payload bandwidth number) */ +struct link_mst_stream_allocation { + /* DIG front */ + const struct stream_encoder *stream_enc; + /* HPO DP Stream Encoder */ + const struct hpo_dp_stream_encoder *hpo_dp_stream_enc; + /* associate DRM payload table with DC stream encoder */ + uint8_t vcp_id; + /* number of slots required for the DP stream in transport packet */ + uint8_t slot_count; +}; + +#define MAX_CONTROLLER_NUM 6 + +/* DP MST stream allocation table */ +struct link_mst_stream_allocation_table { + /* number of DP video streams */ + int stream_count; + /* array of stream allocations */ + struct link_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM]; +}; + +/* PSR feature flags */ +struct psr_settings { + bool psr_feature_enabled; // PSR is supported by sink + bool psr_allow_active; // PSR is currently active + enum dc_psr_version psr_version; // Internal PSR version, determined based on DPCD + bool psr_vtotal_control_support; // Vtotal control is supported by sink + unsigned long long psr_dirty_rects_change_timestamp_ns; // for delay of enabling PSR-SU + + /* These parameters are calculated in Driver, + * based on display timing and Sink capabilities. + * If VBLANK region is too small and Sink takes a long time + * to set up RFB, it may take an extra frame to enter PSR state. + */ + bool psr_frame_capture_indication_req; + unsigned int psr_sdp_transmit_line_num_deadline; + uint8_t force_ffu_mode; + unsigned int psr_power_opt; +}; + +/* To split out "global" and "per-panel" config settings. + * Add a struct dc_panel_config under dc_link + */ +struct dc_panel_config { + /* extra panel power sequence parameters */ + struct pps { + unsigned int extra_t3_ms; + unsigned int extra_t7_ms; + unsigned int extra_delay_backlight_off; + unsigned int extra_post_t7_ms; + unsigned int extra_pre_t11_ms; + unsigned int extra_t12_ms; + unsigned int extra_post_OUI_ms; + } pps; + /* nit brightness */ + struct nits_brightness { + unsigned int peak; /* nits */ + unsigned int max_avg; /* nits */ + unsigned int min; /* 1/10000 nits */ + unsigned int max_nonboost_brightness_millinits; + unsigned int min_brightness_millinits; + } nits_brightness; + /* PSR */ + struct psr { + bool disable_psr; + bool disallow_psrsu; + bool rc_disable; + bool rc_allow_static_screen; + bool rc_allow_fullscreen_VPB; + } psr; + /* ABM */ + struct varib { + unsigned int varibright_feature_enable; + unsigned int def_varibright_level; + unsigned int abm_config_setting; + } varib; + /* edp DSC */ + struct dsc { + bool disable_dsc_edp; + unsigned int force_dsc_edp_policy; + } dsc; + /* eDP ILR */ + struct ilr { + bool optimize_edp_link_rate; /* eDP ILR */ + } ilr; +}; + +/* + * USB4 DPIA BW ALLOCATION STRUCTS + */ +struct dc_dpia_bw_alloc { + int sink_verified_bw; // The Verified BW that sink can allocated and use that has been verified already + int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated + int sink_max_bw; // The Max BW that sink can require/support + int estimated_bw; // The estimated available BW for this DPIA + int bw_granularity; // BW Granularity + bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3: DP-Tx & Dpia & CM + bool response_ready; // Response ready from the CM side +}; + +#define MAX_SINKS_PER_LINK 4 + +enum dc_hpd_enable_select { + HPD_EN_FOR_ALL_EDP = 0, + HPD_EN_FOR_PRIMARY_EDP_ONLY, + HPD_EN_FOR_SECONDARY_EDP_ONLY, +}; + #endif /* DC_TYPES_H_ */ 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 fb0dec4ed3a6..9fc48208c2e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -148,7 +148,7 @@ static bool dmub_abm_set_level(struct abm *abm, uint32_t level) int edp_num; uint8_t panel_mask = 0; - get_edp_links(dc->dc, edp_links, &edp_num); + dc_get_edp_links(dc->dc, edp_links, &edp_num); for (i = 0; i < edp_num; i++) { if (edp_links[i]->link_status.link_active) 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 74005b9d352a..289e42070ece 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h @@ -26,8 +26,9 @@ #ifndef _DMUB_PSR_H_ #define _DMUB_PSR_H_ -#include "os_types.h" -#include "dc_link.h" +#include "dc_types.h" +struct dc_link; +struct dmub_psr_funcs; struct dmub_psr { 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 0d4d3d586166..cb3bb5402c52 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 @@ -1739,7 +1739,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) get_edp_links_with_sink(dc, edp_links_with_sink, &edp_with_sink_num); - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (hws->funcs.init_pipes) hws->funcs.init_pipes(dc, context); 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 a1a29c508394..e255519cb5cc 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 @@ -726,11 +726,15 @@ void dcn10_hubp_pg_control( } } -static void power_on_plane( +static void power_on_plane_resources( struct dce_hwseq *hws, int plane_id) { DC_LOGGER_INIT(hws->ctx->logger); + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, plane_id, true); + if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -1237,11 +1241,15 @@ void dcn10_plane_atomic_power_down(struct dc *dc, hws->funcs.hubp_pg_control(hws, hubp->inst, false); dpp->funcs->dpp_reset(dpp); + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); DC_LOG_DEBUG( "Power gated front end %d\n", hubp->inst); } + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); } /* disable HW used by plane. @@ -1638,7 +1646,7 @@ void dcn10_power_down_on_boot(struct dc *dc) int edp_num; int i = 0; - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num) edp_link = edp_links[0]; @@ -2462,7 +2470,7 @@ static void dcn10_enable_plane( undo_DEGVIDCN10_253_wa(dc); - power_on_plane(dc->hwseq, + power_on_plane_resources(dc->hwseq, pipe_ctx->plane_res.hubp->inst); /* enable DCFCLK current DCHUB */ @@ -3385,7 +3393,9 @@ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) for (test_pipe = pipe_ctx->top_pipe; test_pipe; test_pipe = test_pipe->top_pipe) { // Skip invisible layer and pipe-split plane on same layer - if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer) + if (!test_pipe->plane_state || + !test_pipe->plane_state->visible || + test_pipe->plane_state->layer_index == cur_layer) continue; r2 = test_pipe->plane_res.scl_data.recout; 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 b83873a3a534..0789129727e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1121,11 +1121,15 @@ void dcn20_blank_pixel_data( } -static void dcn20_power_on_plane( +static void dcn20_power_on_plane_resources( struct dce_hwseq *hws, struct pipe_ctx *pipe_ctx) { DC_LOGGER_INIT(hws->ctx->logger); + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true); + if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -1149,7 +1153,7 @@ static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, //if (dc->debug.sanity_checks) { // dcn10_verify_allow_pstate_change_high(dc); //} - dcn20_power_on_plane(dc->hwseq, pipe_ctx); + dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx); /* enable DCFCLK current DCHUB */ pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); 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 5f9079d3943a..9d08127d209b 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 @@ -28,6 +28,7 @@ #include "dcn30_dio_stream_encoder.h" #include "reg_helper.h" #include "hw_shared.h" +#include "dc.h" #include "core_types.h" #include <linux/delay.h> 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 df787fcf8e86..b4df540c0c61 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -567,7 +567,7 @@ void dcn30_init_hw(struct dc *dc) struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num) edp_link = edp_links[0]; if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 7f34418e6308..7d2b982506fd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -66,17 +66,8 @@ void dccg31_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 1); } else { - //DTO must be enabled to generate a 0Hz clock output - if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) { - REG_UPDATE(DPPCLK_DTO_CTRL, - DPPCLK_DTO_ENABLE[dpp_inst], 1); - REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, - DPPCLK0_DTO_PHASE, 0, - DPPCLK0_DTO_MODULO, 1); - } else { - REG_UPDATE(DPPCLK_DTO_CTRL, - DPPCLK_DTO_ENABLE[dpp_inst], 0); - } + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 0); } dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c index 0b317ed31f91..5b7ad38f85e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c @@ -26,7 +26,6 @@ #include "dc_bios_types.h" #include "dcn31_hpo_dp_link_encoder.h" #include "reg_helper.h" -#include "dc_link.h" #include "stream_encoder.h" #define DC_LOGGER \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c index d76f55a12eb4..0278bae50a9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c @@ -26,7 +26,7 @@ #include "dc_bios_types.h" #include "dcn31_hpo_dp_stream_encoder.h" #include "reg_helper.h" -#include "dc_link.h" +#include "dc.h" #define DC_LOGGER \ enc3->base.ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c index 0b769ee71405..081ce168f621 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c @@ -289,8 +289,31 @@ static void dccg314_set_valid_pixel_rate( dccg314_set_dtbclk_dto(dccg, &dto_params); } +static void dccg314_dpp_root_clock_control( + struct dccg *dccg, + unsigned int dpp_inst, + bool clock_on) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (clock_on) { + /* turn off the DTO and leave phase/modulo at max */ + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 0); + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, 0xFF, + DPPCLK0_DTO_MODULO, 0xFF); + } else { + /* turn on the DTO to generate a 0hz clock */ + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 1); + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, 0, + DPPCLK0_DTO_MODULO, 1); + } +} + static const struct dccg_funcs dccg314_funcs = { .update_dpp_dto = dccg31_update_dpp_dto, + .dpp_root_clock_control = dccg314_dpp_root_clock_control, .get_dccg_ref_freq = dccg31_get_dccg_ref_freq, .dccg_init = dccg31_init, .set_dpstreamclk = dccg314_set_dpstreamclk, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index 575d3501c848..0d180f13803d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -390,6 +390,16 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) pix_per_cycle); } +void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on) +{ + if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp) + return; + + if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) + hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control( + hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on); +} + void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) { struct dc_context *ctx = hws->ctx; diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h index c419d3dbdfee..c786d5e6a428 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h @@ -43,4 +43,6 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); +void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); + #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 343f4d9dd5e3..5267e901a35c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -137,6 +137,7 @@ static const struct hwseq_private_funcs dcn314_private_funcs = { .plane_atomic_disable = dcn20_plane_atomic_disable, .plane_atomic_power_down = dcn10_plane_atomic_power_down, .enable_power_gating_plane = dcn314_enable_power_gating_plane, + .dpp_root_clock_control = dcn314_dpp_root_clock_control, .hubp_pg_control = dcn314_hubp_pg_control, .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn314_update_odm, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 9ffba4c6fe55..30129fb9c27a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -887,6 +887,7 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .enable_z9_disable_interface = true, + .minimum_z8_residency_time = 2000, .psr_skip_crtc_disable = true, .disable_dmcu = true, .force_abm_enable = false, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hpo_dp_link_encoder.c index 4dbad8d4b4fc..8af01f579690 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hpo_dp_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hpo_dp_link_encoder.c @@ -26,7 +26,6 @@ #include "dcn31/dcn31_hpo_dp_link_encoder.h" #include "dcn32_hpo_dp_link_encoder.h" #include "reg_helper.h" -#include "dc_link.h" #include "stream_encoder.h" #define DC_LOGGER \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index 9d14045cccd6..823f29c292d0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -828,7 +828,7 @@ void dcn32_init_hw(struct dc *dc) struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link; - get_edp_links(dc, edp_links, &edp_num); + dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num) { for (i = 0; i < edp_num; i++) { edp_link = edp_links[i]; @@ -912,6 +912,7 @@ void dcn32_init_hw(struct dc *dc) if (dc->ctx->dmub_srv) { dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 4b7abb4af623..a518243792df 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -2021,7 +2021,7 @@ int dcn32_populate_dml_pipes_from_context( // In general cases we want to keep the dram clock change requirement // (prefer configs that support MCLK switch). Only override to false // for SubVP - if (subvp_in_use) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use) context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false; else context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; @@ -2077,6 +2077,14 @@ static struct resource_funcs dcn32_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN32 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn32_resource_construct( uint8_t num_virtual_links, @@ -2119,7 +2127,7 @@ static bool dcn32_resource_construct( pool->base.res_cap = &res_cap_dcn32; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index 55f918b44077..1a805dcdf534 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -1626,6 +1626,14 @@ static struct resource_funcs dcn321_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN321 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn321_resource_construct( uint8_t num_virtual_links, @@ -1668,7 +1676,7 @@ static bool dcn321_resource_construct( pool->base.res_cap = &res_cap_dcn321; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index d3ba65efe1d2..f3cfc144e358 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -973,7 +973,8 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { struct dc_link *link = context->streams[0]->sink->link; struct dc_stream_status *stream_status = &context->stream_status[0]; - bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > 1000.0; + int minmum_z8_residency = dc->debug.minimum_z8_residency_time > 0 ? dc->debug.minimum_z8_residency_time : 1000; + bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z8_residency; bool is_pwrseq0 = link->link_index == 0; if (dc_extended_blank_supported(dc)) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index 4fa636364793..fdfb19337ea6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -368,7 +368,9 @@ void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) dc_assert_fp_enabled(); if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) { - context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || + context->bw_ctx.dml.soc.dram_clock_change_latency_us == 0) + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].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_A].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_A].dml_input.sr_exit_time_us; } @@ -520,6 +522,20 @@ void dcn30_fpu_calculate_wm_and_dlg( pipe_idx++; } + // WA: restrict FPO to use first non-strobe mode (NV24 BW issue) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && + dc->dml.soc.num_chans <= 4 && + context->bw_ctx.dml.vba.DRAMSpeed <= 1700 && + context->bw_ctx.dml.vba.DRAMSpeed >= 1500) { + + for (i = 0; i < dc->dml.soc.num_states; i++) { + if (dc->dml.soc.clock_limits[i].dram_speed_mts > 1700) { + context->bw_ctx.dml.vba.DRAMSpeed = dc->dml.soc.clock_limits[i].dram_speed_mts; + break; + } + } + } + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); if (!pstate_en) 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 c3d75e56410c..899105da0433 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 @@ -25,7 +25,6 @@ #ifdef CONFIG_DRM_AMD_DC_DCN #include "dc.h" -#include "dc_link.h" #include "../display_mode_lib.h" #include "display_mode_vba_30.h" #include "../dml_inline_defs.h" 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 index 27f488405335..2b57f5b2362a 100644 --- 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 @@ -24,7 +24,6 @@ */ #include "dc.h" -#include "dc_link.h" #include "../display_mode_lib.h" #include "../dcn30/display_mode_vba_30.h" #include "display_mode_vba_31.h" diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index acda3e1babd4..3bbc46a67335 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -149,8 +149,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = { .num_states = 5, .sr_exit_time_us = 16.5, .sr_enter_plus_exit_time_us = 18.5, - .sr_exit_z8_time_us = 210.0, - .sr_enter_plus_exit_z8_time_us = 310.0, + .sr_exit_z8_time_us = 268.0, + .sr_enter_plus_exit_z8_time_us = 393.0, .writeback_latency_us = 12.0, .dram_channel_width_bytes = 4, .round_trip_ping_latency_dcfclk_cycles = 106, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index c843b394aeb4..461ab6d2030e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -27,7 +27,6 @@ #define UNIT_TEST 0 #if !UNIT_TEST #include "dc.h" -#include "dc_link.h" #endif #include "../display_mode_lib.h" #include "display_mode_vba_314.h" diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 3b2a014ccf8f..02d99b6bfe5e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -24,7 +24,6 @@ */ #include "dc.h" -#include "dc_link.h" #include "../display_mode_lib.h" #include "display_mode_vba_32.h" #include "../dml_inline_defs.h" @@ -810,7 +809,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->SwathHeightY[k], v->SwathHeightC[k], TWait, - v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ || + v->DCFCLKPerState[mode_lib->vba.VoltageLevel] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ &v->DSTXAfterScaler[k], @@ -3309,7 +3309,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->swath_width_chroma_ub_this_state[k], v->SwathHeightYThisState[k], v->SwathHeightCThisState[k], v->TWait, - v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKState[i][j] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h index 500b3dd6052d..d98e36a9a09c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h @@ -53,6 +53,7 @@ #define BPP_BLENDED_PIPE 0xffffffff #define MEM_STROBE_FREQ_MHZ 1600 +#define MIN_DCFCLK_FREQ_MHZ 200 #define MEM_STROBE_MAX_DELIVERY_TIME_US 60.0 struct display_mode_lib; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index b80cef70fa60..383a409a3f54 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -106,16 +106,16 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .clock_limits = { { .state = 0, - .dcfclk_mhz = 1564.0, - .fabricclk_mhz = 400.0, - .dispclk_mhz = 2150.0, - .dppclk_mhz = 2150.0, + .dcfclk_mhz = 1434.0, + .fabricclk_mhz = 2250.0, + .dispclk_mhz = 1720.0, + .dppclk_mhz = 1720.0, .phyclk_mhz = 810.0, .phyclk_d18_mhz = 667.0, - .phyclk_d32_mhz = 625.0, + .phyclk_d32_mhz = 313.0, .socclk_mhz = 1200.0, - .dscclk_mhz = 716.667, - .dram_speed_mts = 1600.0, + .dscclk_mhz = 573.333, + .dram_speed_mts = 16000.0, .dtbclk_mhz = 1564.0, }, }, @@ -125,14 +125,14 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .sr_exit_z8_time_us = 285.0, .sr_enter_plus_exit_z8_time_us = 320, .writeback_latency_us = 12.0, - .round_trip_ping_latency_dcfclk_cycles = 263, + .round_trip_ping_latency_dcfclk_cycles = 207, .urgent_latency_pixel_data_only_us = 4, .urgent_latency_pixel_mixed_with_vm_data_us = 4, .urgent_latency_vm_data_only_us = 4, - .fclk_change_latency_us = 20, - .usr_retraining_latency_us = 2, - .smn_latency_us = 2, - .mall_allocated_for_dcn_mbytes = 64, + .fclk_change_latency_us = 7, + .usr_retraining_latency_us = 0, + .smn_latency_us = 0, + .mall_allocated_for_dcn_mbytes = 32, .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, 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 ce006762f257..ad6acd1b34e1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -148,18 +148,21 @@ struct dccg_funcs { struct dccg *dccg, int inst); -void (*set_pixel_rate_div)( - struct dccg *dccg, - uint32_t otg_inst, - enum pixel_rate_div k1, - enum pixel_rate_div k2); - -void (*set_valid_pixel_rate)( - struct dccg *dccg, - int ref_dtbclk_khz, - int otg_inst, - int pixclk_khz); + void (*set_pixel_rate_div)(struct dccg *dccg, + uint32_t otg_inst, + enum pixel_rate_div k1, + enum pixel_rate_div k2); + void (*set_valid_pixel_rate)( + struct dccg *dccg, + int ref_dtbclk_khz, + int otg_inst, + int pixclk_khz); + + void (*dpp_root_clock_control)( + struct dccg *dccg, + unsigned int dpp_inst, + bool clock_on); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index a819f0f97c5f..b95ae9596c3b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -275,20 +275,6 @@ enum dc_lut_mode { LUT_RAM_B }; -enum symclk_state { - SYMCLK_OFF_TX_OFF, - SYMCLK_ON_TX_ON, - SYMCLK_ON_TX_OFF, -}; - -struct phy_state { - struct { - uint8_t otg : 1; - uint8_t reserved : 7; - } symclk_ref_cnts; - enum symclk_state symclk_state; -}; - /** * speakersToChannels * 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 ec572a9e4054..dbe7afa9d3a2 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 @@ -75,58 +75,6 @@ struct encoder_feature_support { bool fec_supported; }; -union dpcd_psr_configuration { - struct { - unsigned char ENABLE : 1; - unsigned char TRANSMITTER_ACTIVE_IN_PSR : 1; - unsigned char CRC_VERIFICATION : 1; - unsigned char FRAME_CAPTURE_INDICATION : 1; - /* For eDP 1.4, PSR v2*/ - unsigned char LINE_CAPTURE_INDICATION : 1; - /* For eDP 1.4, PSR v2*/ - unsigned char IRQ_HPD_WITH_CRC_ERROR : 1; - unsigned char ENABLE_PSR2 : 1; - /* For eDP 1.5, PSR v2 w/ early transport */ - unsigned char EARLY_TRANSPORT_ENABLE : 1; - } bits; - unsigned char raw; -}; - -union dpcd_alpm_configuration { - struct { - unsigned char ENABLE : 1; - unsigned char IRQ_HPD_ENABLE : 1; - unsigned char RESERVED : 6; - } bits; - unsigned char raw; -}; - -union dpcd_sink_active_vtotal_control_mode { - struct { - unsigned char ENABLE : 1; - unsigned char RESERVED : 7; - } bits; - unsigned char raw; -}; - -union psr_error_status { - struct { - unsigned char LINK_CRC_ERROR :1; - unsigned char RFB_STORAGE_ERROR :1; - unsigned char VSC_SDP_ERROR :1; - unsigned char RESERVED :5; - } bits; - unsigned char raw; -}; - -union psr_sink_psr_status { - struct { - unsigned char SINK_SELF_REFRESH_STATUS :3; - unsigned char RESERVED :5; - } bits; - unsigned char raw; -}; - struct link_encoder { const struct link_encoder_funcs *funcs; int32_t aux_channel_offset; 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 bb5ad70d4266..c4fbbf08ef86 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 @@ -30,7 +30,6 @@ #include "audio_types.h" #include "hw_shared.h" -#include "dc_link.h" struct dc_bios; struct dc_context; 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 a4d61bb724b6..39bd53b79020 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 @@ -115,6 +115,10 @@ struct hwseq_private_funcs { void (*plane_atomic_disable)(struct dc *dc, struct pipe_ctx *pipe_ctx); void (*enable_power_gating_plane)(struct dce_hwseq *hws, bool enable); + void (*dpp_root_clock_control)( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool clock_on); void (*dpp_pg_control)(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h index e70fa0059223..6a346a41f07b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -38,7 +38,6 @@ * into this file and prefix it with "link_". */ #include "core_types.h" -#include "dc_link.h" struct link_init_data { const struct dc *dc; diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index 942300e0bd92..7f36d733bfca 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -1027,20 +1027,3 @@ void dc_link_set_preferred_training_settings(struct dc *dc, if (skip_immediate_retrain == false) dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); } - -void dc_link_set_test_pattern(struct dc_link *link, - enum dp_test_pattern test_pattern, - enum dp_test_pattern_color_space test_pattern_color_space, - const struct link_training_settings *p_link_settings, - const unsigned char *p_custom_pattern, - unsigned int cust_pattern_size) -{ - if (link != NULL) - dc_link_dp_set_test_pattern( - link, - test_pattern, - test_pattern_color_space, - p_link_settings, - p_custom_pattern, - cust_pattern_size); -} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f70025ef7b69..9839ec222875 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -1329,3 +1329,102 @@ const struct dc_link_status *link_get_status(const struct dc_link *link) return &link->link_status; } + +static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) +{ + if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { + BREAK_TO_DEBUGGER(); + return false; + } + + dc_sink_retain(sink); + + dc_link->remote_sinks[dc_link->sink_count] = sink; + dc_link->sink_count++; + + return true; +} + +struct dc_sink *dc_link_add_remote_sink( + struct dc_link *link, + const uint8_t *edid, + int len, + struct dc_sink_init_data *init_data) +{ + struct dc_sink *dc_sink; + enum dc_edid_status edid_status; + + if (len > DC_MAX_EDID_BUFFER_SIZE) { + dm_error("Max EDID buffer size breached!\n"); + return NULL; + } + + if (!init_data) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + if (!init_data->link) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dc_sink = dc_sink_create(init_data); + + if (!dc_sink) + return NULL; + + memmove(dc_sink->dc_edid.raw_edid, edid, len); + dc_sink->dc_edid.length = len; + + if (!link_add_remote_sink_helper( + link, + dc_sink)) + goto fail_add_sink; + + edid_status = dm_helpers_parse_edid_caps( + link, + &dc_sink->dc_edid, + &dc_sink->edid_caps); + + /* + * Treat device as no EDID device if EDID + * parsing fails + */ + if (edid_status != EDID_OK && edid_status != EDID_PARTIAL_VALID) { + dc_sink->dc_edid.length = 0; + dm_error("Bad EDID, status%d!\n", edid_status); + } + + return dc_sink; + +fail_add_sink: + dc_sink_release(dc_sink); + return NULL; +} + +void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) +{ + int i; + + if (!link->sink_count) { + BREAK_TO_DEBUGGER(); + return; + } + + for (i = 0; i < link->sink_count; i++) { + if (link->remote_sinks[i] == sink) { + dc_sink_release(sink); + link->remote_sinks[i] = NULL; + + /* shrink array to remove empty place */ + while (i < link->sink_count - 1) { + link->remote_sinks[i] = link->remote_sinks[i+1]; + i++; + } + link->remote_sinks[i] = NULL; + link->sink_count--; + return; + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index aeb26a4d539e..8aaf14afa427 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -274,14 +274,18 @@ static bool dc_link_construct_phy(struct dc_link *link, link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; switch (link->dc->config.allow_edp_hotplug_detection) { - case 1: // only the 1st eDP handles hotplug + case HPD_EN_FOR_ALL_EDP: + link->irq_source_hpd_rx = + dal_irq_get_rx_source(link->hpd_gpio); + break; + case HPD_EN_FOR_PRIMARY_EDP_ONLY: if (link->link_index == 0) link->irq_source_hpd_rx = dal_irq_get_rx_source(link->hpd_gpio); else link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; - case 2: // only the 2nd eDP handles hotplug + case HPD_EN_FOR_SECONDARY_EDP_ONLY: if (link->link_index == 1) link->irq_source_hpd_rx = dal_irq_get_rx_source(link->hpd_gpio); @@ -289,6 +293,7 @@ static bool dc_link_construct_phy(struct dc_link *link, link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; default: + link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; } } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c index 32f48a48e9dd..cbfa9343ffaf 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c @@ -26,7 +26,6 @@ #include "dc.h" #include "inc/core_status.h" -#include "dc_link.h" #include "dpcd_defs.h" #include "link_dp_dpia.h" diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c index f69e681b3b5b..1ecf1d857359 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c @@ -27,7 +27,6 @@ // USB4 DPIA BANDWIDTH ALLOCATION LOGIC /*********************************************************************/ #include "dc.h" -#include "dc_link.h" #include "link_dp_dpia_bw.h" #include "drm_dp_helper_dc.h" #include "link_dpcd.h" diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index e60da0532c53..4ded5f9cdecc 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -29,7 +29,6 @@ #include "link_dp_training_dpia.h" #include "dc.h" #include "inc/core_status.h" -#include "dc_link.h" #include "dpcd_defs.h" #include "link_dp_dpia.h" diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index a76da0131add..9c20516be066 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -130,12 +130,13 @@ void dmub_dcn32_reset(struct dmub_srv *dmub) REG_WRITE(DMCUB_INBOX1_WPTR, 0); REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_WPTR, 0); REG_WRITE(DMCUB_SCRATCH0, 0); } void dmub_dcn32_reset_release(struct dmub_srv *dmub) { - REG_WRITE(DMCUB_GPINT_DATAIN1, 0); 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); 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 18b9173d5a96..cd870af5fd25 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -34,10 +34,6 @@ struct ddc; struct irq_manager; -enum { - MAX_CONTROLLER_NUM = 6 -}; - enum dp_power_state { DP_POWER_STATE_D0 = 1, DP_POWER_STATE_D3 @@ -60,28 +56,6 @@ enum { DATA_EFFICIENCY_128b_132b_x10000 = 9646, /* 96.71% data efficiency x 99.75% downspread factor */ }; -enum link_training_result { - LINK_TRAINING_SUCCESS, - LINK_TRAINING_CR_FAIL_LANE0, - LINK_TRAINING_CR_FAIL_LANE1, - LINK_TRAINING_CR_FAIL_LANE23, - /* CR DONE bit is cleared during EQ step */ - LINK_TRAINING_EQ_FAIL_CR, - /* CR DONE bit is cleared but LANE0_CR_DONE is set during EQ step */ - LINK_TRAINING_EQ_FAIL_CR_PARTIAL, - /* other failure during EQ step */ - LINK_TRAINING_EQ_FAIL_EQ, - LINK_TRAINING_LQA_FAIL, - /* one of the CR,EQ or symbol lock is dropped */ - LINK_TRAINING_LINK_LOSS, - /* Abort link training (because sink unplugged) */ - LINK_TRAINING_ABORT, - DP_128b_132b_LT_FAILED, - DP_128b_132b_MAX_LOOP_COUNT_REACHED, - DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT, - DP_128b_132b_CDS_DONE_TIMEOUT, -}; - enum lttpr_mode { LTTPR_MODE_UNKNOWN, LTTPR_MODE_NON_LTTPR, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 6e79d3352d0b..bdacc0a7b61d 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -36,6 +36,8 @@ #define amdgpu_dpm_enable_bapm(adev, e) \ ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e))) +#define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev)) + int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1432,15 +1434,24 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) { - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - struct smu_context *smu = adev->powerplay.pp_handle; + if (is_support_sw_smu(adev)) { + struct smu_context *smu = adev->powerplay.pp_handle; - if ((is_support_sw_smu(adev) && smu->od_enabled) || - (is_support_sw_smu(adev) && smu->is_apu) || - (!is_support_sw_smu(adev) && hwmgr->od_enabled)) - return true; + return (smu->od_enabled || smu->is_apu); + } else { + struct pp_hwmgr *hwmgr; - return false; + /* + * dpm on some legacy asics don't carry od_enabled member + * as its pp_handle is casted directly from adev. + */ + if (amdgpu_dpm_is_legacy_dpm(adev)) + return false; + + hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; + + return hwmgr->od_enabled; + } } int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, |