mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
amd-drm-fixes-6.17-2025-08-20:
amdgpu: - Replay fixes - SMU14 fix - Null check DC fixes - DCE6 DC fixes - Misc DC fixes -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCaKYjMgAKCRC93/aFa7yZ 2BHyAQCZLYCzi23q0qGS7vPS7dTzdvwji7luhWqqBX7lTGmB2AD/U3fE9kVg6Itv PjPxfA6E3A1UDJGKdSaJkFtXQRx4+wo= =LUbK -----END PGP SIGNATURE----- Merge tag 'amd-drm-fixes-6.17-2025-08-20' of https://gitlab.freedesktop.org/agd5f/linux into drm-fixes amd-drm-fixes-6.17-2025-08-20: amdgpu: - Replay fixes - SMU14 fix - Null check DC fixes - DCE6 DC fixes - Misc DC fixes Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://lore.kernel.org/r/20250820194636.101975-1-alexander.deucher@amd.com
This commit is contained in:
commit
dbb2c3adc4
@ -7792,6 +7792,9 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
|
|||||||
struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
|
struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (WARN_ON(unlikely(!old_con_state || !new_con_state)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
trace_amdgpu_dm_connector_atomic_check(new_con_state);
|
trace_amdgpu_dm_connector_atomic_check(new_con_state);
|
||||||
|
|
||||||
if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
|
if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
|
||||||
|
@ -299,6 +299,25 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
|||||||
irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id);
|
irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
struct dc *dc = adev->dm.dc;
|
||||||
|
struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
|
||||||
|
struct psr_settings *psr = &acrtc_state->stream->link->psr_settings;
|
||||||
|
struct replay_settings *pr = &acrtc_state->stream->link->replay_settings;
|
||||||
|
bool sr_supported = (psr->psr_version != DC_PSR_VERSION_UNSUPPORTED) ||
|
||||||
|
pr->config.replay_supported;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPS & self-refresh feature can cause vblank counter resets between
|
||||||
|
* vblank disable and enable.
|
||||||
|
* It may cause system stuck due to waiting for the vblank counter.
|
||||||
|
* Call this function to estimate missed vblanks by using timestamps and
|
||||||
|
* update the vblank counter in DRM.
|
||||||
|
*/
|
||||||
|
if (dc->caps.ips_support &&
|
||||||
|
dc->config.disable_ips != DMUB_IPS_DISABLE_ALL &&
|
||||||
|
sr_supported && vblank->config.disable_immediate)
|
||||||
|
drm_crtc_vblank_restore(crtc);
|
||||||
|
|
||||||
/* vblank irq on -> Only need vupdate irq in vrr mode */
|
/* vblank irq on -> Only need vupdate irq in vrr mode */
|
||||||
if (amdgpu_dm_crtc_vrr_active(acrtc_state))
|
if (amdgpu_dm_crtc_vrr_active(acrtc_state))
|
||||||
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true);
|
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true);
|
||||||
|
@ -174,11 +174,8 @@ static struct graphics_object_id bios_parser_get_connector_id(
|
|||||||
return object_id;
|
return object_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tbl->ucNumberOfObjects <= i) {
|
if (tbl->ucNumberOfObjects <= i)
|
||||||
dm_error("Can't find connector id %d in connector table of size %d.\n",
|
|
||||||
i, tbl->ucNumberOfObjects);
|
|
||||||
return object_id;
|
return object_id;
|
||||||
}
|
|
||||||
|
|
||||||
id = le16_to_cpu(tbl->asObjects[i].usObjectID);
|
id = le16_to_cpu(tbl->asObjects[i].usObjectID);
|
||||||
object_id = object_id_from_bios_object_id(id);
|
object_id = object_id_from_bios_object_id(id);
|
||||||
|
@ -993,7 +993,7 @@ static enum bp_result set_pixel_clock_v3(
|
|||||||
allocation.sPCLKInput.usFbDiv =
|
allocation.sPCLKInput.usFbDiv =
|
||||||
cpu_to_le16((uint16_t)bp_params->feedback_divider);
|
cpu_to_le16((uint16_t)bp_params->feedback_divider);
|
||||||
allocation.sPCLKInput.ucFracFbDiv =
|
allocation.sPCLKInput.ucFracFbDiv =
|
||||||
(uint8_t)bp_params->fractional_feedback_divider;
|
(uint8_t)(bp_params->fractional_feedback_divider / 100000);
|
||||||
allocation.sPCLKInput.ucPostDiv =
|
allocation.sPCLKInput.ucPostDiv =
|
||||||
(uint8_t)bp_params->pixel_clock_post_divider;
|
(uint8_t)bp_params->pixel_clock_post_divider;
|
||||||
|
|
||||||
|
@ -72,9 +72,9 @@ static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
|
|||||||
/* ClocksStateLow */
|
/* ClocksStateLow */
|
||||||
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
|
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
|
||||||
/* ClocksStateNominal */
|
/* ClocksStateNominal */
|
||||||
{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
|
{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 },
|
||||||
/* ClocksStatePerformance */
|
/* ClocksStatePerformance */
|
||||||
{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
|
{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 } };
|
||||||
|
|
||||||
int dentist_get_divider_from_did(int did)
|
int dentist_get_divider_from_did(int did)
|
||||||
{
|
{
|
||||||
@ -391,8 +391,6 @@ static void dce_pplib_apply_display_requirements(
|
|||||||
{
|
{
|
||||||
struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
|
struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
|
||||||
|
|
||||||
pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
|
|
||||||
|
|
||||||
dce110_fill_display_configs(context, pp_display_cfg);
|
dce110_fill_display_configs(context, pp_display_cfg);
|
||||||
|
|
||||||
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
||||||
@ -405,11 +403,9 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||||||
{
|
{
|
||||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||||
struct dm_pp_power_level_change_request level_change_req;
|
struct dm_pp_power_level_change_request level_change_req;
|
||||||
int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
|
const int max_disp_clk =
|
||||||
|
clk_mgr_dce->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz;
|
||||||
/*TODO: W/A for dal3 linux, investigate why this works */
|
int patched_disp_clk = MIN(max_disp_clk, context->bw_ctx.bw.dce.dispclk_khz);
|
||||||
if (!clk_mgr_dce->dfs_bypass_active)
|
|
||||||
patched_disp_clk = patched_disp_clk * 115 / 100;
|
|
||||||
|
|
||||||
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
||||||
/* get max clock state from PPLIB */
|
/* get max clock state from PPLIB */
|
||||||
|
@ -120,9 +120,15 @@ void dce110_fill_display_configs(
|
|||||||
const struct dc_state *context,
|
const struct dc_state *context,
|
||||||
struct dm_pp_display_configuration *pp_display_cfg)
|
struct dm_pp_display_configuration *pp_display_cfg)
|
||||||
{
|
{
|
||||||
|
struct dc *dc = context->clk_mgr->ctx->dc;
|
||||||
int j;
|
int j;
|
||||||
int num_cfgs = 0;
|
int num_cfgs = 0;
|
||||||
|
|
||||||
|
pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
|
||||||
|
pp_display_cfg->disp_clk_khz = dc->clk_mgr->clks.dispclk_khz;
|
||||||
|
pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
|
||||||
|
pp_display_cfg->crtc_index = dc->res_pool->res_cap->num_timing_generator;
|
||||||
|
|
||||||
for (j = 0; j < context->stream_count; j++) {
|
for (j = 0; j < context->stream_count; j++) {
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
@ -164,6 +170,23 @@ void dce110_fill_display_configs(
|
|||||||
cfg->v_refresh /= stream->timing.h_total;
|
cfg->v_refresh /= stream->timing.h_total;
|
||||||
cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
|
cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
|
||||||
/ stream->timing.v_total;
|
/ stream->timing.v_total;
|
||||||
|
|
||||||
|
/* Find first CRTC index and calculate its line time.
|
||||||
|
* This is necessary for DPM on SI GPUs.
|
||||||
|
*/
|
||||||
|
if (cfg->pipe_idx < pp_display_cfg->crtc_index) {
|
||||||
|
const struct dc_crtc_timing *timing =
|
||||||
|
&context->streams[0]->timing;
|
||||||
|
|
||||||
|
pp_display_cfg->crtc_index = cfg->pipe_idx;
|
||||||
|
pp_display_cfg->line_time_in_us =
|
||||||
|
timing->h_total * 10000 / timing->pix_clk_100hz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num_cfgs) {
|
||||||
|
pp_display_cfg->crtc_index = 0;
|
||||||
|
pp_display_cfg->line_time_in_us = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_display_cfg->display_count = num_cfgs;
|
pp_display_cfg->display_count = num_cfgs;
|
||||||
@ -223,25 +246,8 @@ void dce11_pplib_apply_display_requirements(
|
|||||||
pp_display_cfg->min_engine_clock_deep_sleep_khz
|
pp_display_cfg->min_engine_clock_deep_sleep_khz
|
||||||
= context->bw_ctx.bw.dce.sclk_deep_sleep_khz;
|
= context->bw_ctx.bw.dce.sclk_deep_sleep_khz;
|
||||||
|
|
||||||
pp_display_cfg->avail_mclk_switch_time_us =
|
|
||||||
dce110_get_min_vblank_time_us(context);
|
|
||||||
/* TODO: dce11.2*/
|
|
||||||
pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
|
|
||||||
|
|
||||||
pp_display_cfg->disp_clk_khz = dc->clk_mgr->clks.dispclk_khz;
|
|
||||||
|
|
||||||
dce110_fill_display_configs(context, pp_display_cfg);
|
dce110_fill_display_configs(context, pp_display_cfg);
|
||||||
|
|
||||||
/* TODO: is this still applicable?*/
|
|
||||||
if (pp_display_cfg->display_count == 1) {
|
|
||||||
const struct dc_crtc_timing *timing =
|
|
||||||
&context->streams[0]->timing;
|
|
||||||
|
|
||||||
pp_display_cfg->crtc_index =
|
|
||||||
pp_display_cfg->disp_configs[0].pipe_idx;
|
|
||||||
pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
||||||
dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
|
dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
|
||||||
}
|
}
|
||||||
|
@ -83,22 +83,13 @@ static const struct state_dependent_clocks dce60_max_clks_by_state[] = {
|
|||||||
static int dce60_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
|
static int dce60_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
|
||||||
{
|
{
|
||||||
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||||
int dprefclk_wdivider;
|
struct dc_context *ctx = clk_mgr_base->ctx;
|
||||||
int dp_ref_clk_khz;
|
int dp_ref_clk_khz = 0;
|
||||||
int target_div;
|
|
||||||
|
|
||||||
/* DCE6 has no DPREFCLK_CNTL to read DP Reference Clock source */
|
if (ASIC_REV_IS_TAHITI_P(ctx->asic_id.hw_internal_rev))
|
||||||
|
dp_ref_clk_khz = ctx->dc_bios->fw_info.default_display_engine_pll_frequency;
|
||||||
/* Read the mmDENTIST_DISPCLK_CNTL to get the currently
|
else
|
||||||
* programmed DID DENTIST_DPREFCLK_WDIVIDER*/
|
dp_ref_clk_khz = clk_mgr_base->clks.dispclk_khz;
|
||||||
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
|
|
||||||
|
|
||||||
/* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
|
|
||||||
target_div = dentist_get_divider_from_did(dprefclk_wdivider);
|
|
||||||
|
|
||||||
/* Calculate the current DFS clock, in kHz.*/
|
|
||||||
dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
|
|
||||||
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
|
|
||||||
|
|
||||||
return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz);
|
return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz);
|
||||||
}
|
}
|
||||||
@ -109,8 +100,6 @@ static void dce60_pplib_apply_display_requirements(
|
|||||||
{
|
{
|
||||||
struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
|
struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
|
||||||
|
|
||||||
pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
|
|
||||||
|
|
||||||
dce110_fill_display_configs(context, pp_display_cfg);
|
dce110_fill_display_configs(context, pp_display_cfg);
|
||||||
|
|
||||||
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
|
||||||
@ -123,11 +112,9 @@ static void dce60_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||||||
{
|
{
|
||||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||||
struct dm_pp_power_level_change_request level_change_req;
|
struct dm_pp_power_level_change_request level_change_req;
|
||||||
int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
|
const int max_disp_clk =
|
||||||
|
clk_mgr_dce->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz;
|
||||||
/*TODO: W/A for dal3 linux, investigate why this works */
|
int patched_disp_clk = MIN(max_disp_clk, context->bw_ctx.bw.dce.dispclk_khz);
|
||||||
if (!clk_mgr_dce->dfs_bypass_active)
|
|
||||||
patched_disp_clk = patched_disp_clk * 115 / 100;
|
|
||||||
|
|
||||||
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
||||||
/* get max clock state from PPLIB */
|
/* get max clock state from PPLIB */
|
||||||
|
@ -217,11 +217,24 @@ static bool create_links(
|
|||||||
connectors_num,
|
connectors_num,
|
||||||
num_virtual_links);
|
num_virtual_links);
|
||||||
|
|
||||||
// condition loop on link_count to allow skipping invalid indices
|
/* When getting the number of connectors, the VBIOS reports the number of valid indices,
|
||||||
|
* but it doesn't say which indices are valid, and not every index has an actual connector.
|
||||||
|
* So, if we don't find a connector on an index, that is not an error.
|
||||||
|
*
|
||||||
|
* - There is no guarantee that the first N indices will be valid
|
||||||
|
* - VBIOS may report a higher amount of valid indices than there are actual connectors
|
||||||
|
* - Some VBIOS have valid configurations for more connectors than there actually are
|
||||||
|
* on the card. This may be because the manufacturer used the same VBIOS for different
|
||||||
|
* variants of the same card.
|
||||||
|
*/
|
||||||
for (i = 0; dc->link_count < connectors_num && i < MAX_LINKS; i++) {
|
for (i = 0; dc->link_count < connectors_num && i < MAX_LINKS; i++) {
|
||||||
|
struct graphics_object_id connector_id = bios->funcs->get_connector_id(bios, i);
|
||||||
struct link_init_data link_init_params = {0};
|
struct link_init_data link_init_params = {0};
|
||||||
struct dc_link *link;
|
struct dc_link *link;
|
||||||
|
|
||||||
|
if (connector_id.id == CONNECTOR_ID_UNKNOWN)
|
||||||
|
continue;
|
||||||
|
|
||||||
DC_LOG_DC("BIOS object table - printing link object info for connector number: %d, link_index: %d", i, dc->link_count);
|
DC_LOG_DC("BIOS object table - printing link object info for connector number: %d, link_index: %d", i, dc->link_count);
|
||||||
|
|
||||||
link_init_params.ctx = dc->ctx;
|
link_init_params.ctx = dc->ctx;
|
||||||
|
@ -896,13 +896,13 @@ void dce110_link_encoder_construct(
|
|||||||
enc110->base.id, &bp_cap_info);
|
enc110->base.id, &bp_cap_info);
|
||||||
|
|
||||||
/* Override features with DCE-specific values */
|
/* Override features with DCE-specific values */
|
||||||
if (BP_RESULT_OK == result) {
|
if (result == BP_RESULT_OK) {
|
||||||
enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
|
enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
|
||||||
bp_cap_info.DP_HBR2_EN;
|
bp_cap_info.DP_HBR2_EN;
|
||||||
enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
|
enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
|
||||||
bp_cap_info.DP_HBR3_EN;
|
bp_cap_info.DP_HBR3_EN;
|
||||||
enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
|
enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
|
||||||
} else {
|
} else if (result != BP_RESULT_NORECORD) {
|
||||||
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
|
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
|
||||||
__func__,
|
__func__,
|
||||||
result);
|
result);
|
||||||
@ -1798,13 +1798,13 @@ void dce60_link_encoder_construct(
|
|||||||
enc110->base.id, &bp_cap_info);
|
enc110->base.id, &bp_cap_info);
|
||||||
|
|
||||||
/* Override features with DCE-specific values */
|
/* Override features with DCE-specific values */
|
||||||
if (BP_RESULT_OK == result) {
|
if (result == BP_RESULT_OK) {
|
||||||
enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
|
enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
|
||||||
bp_cap_info.DP_HBR2_EN;
|
bp_cap_info.DP_HBR2_EN;
|
||||||
enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
|
enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
|
||||||
bp_cap_info.DP_HBR3_EN;
|
bp_cap_info.DP_HBR3_EN;
|
||||||
enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
|
enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
|
||||||
} else {
|
} else if (result != BP_RESULT_NORECORD) {
|
||||||
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
|
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
|
||||||
__func__,
|
__func__,
|
||||||
result);
|
result);
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "dc.h"
|
#include "dc.h"
|
||||||
#include "dc_dmub_srv.h"
|
#include "dc_dmub_srv.h"
|
||||||
#include "dc_dp_types.h"
|
|
||||||
#include "dmub/dmub_srv.h"
|
#include "dmub/dmub_srv.h"
|
||||||
#include "core_types.h"
|
#include "core_types.h"
|
||||||
#include "dmub_replay.h"
|
#include "dmub_replay.h"
|
||||||
@ -44,45 +43,21 @@ static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *s
|
|||||||
/*
|
/*
|
||||||
* Enable/Disable Replay.
|
* Enable/Disable Replay.
|
||||||
*/
|
*/
|
||||||
static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst,
|
static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst)
|
||||||
struct dc_link *link)
|
|
||||||
{
|
{
|
||||||
union dmub_rb_cmd cmd;
|
union dmub_rb_cmd cmd;
|
||||||
struct dc_context *dc = dmub->ctx;
|
struct dc_context *dc = dmub->ctx;
|
||||||
uint32_t retry_count;
|
uint32_t retry_count;
|
||||||
enum replay_state state = REPLAY_STATE_0;
|
enum replay_state state = REPLAY_STATE_0;
|
||||||
struct pipe_ctx *pipe_ctx = NULL;
|
|
||||||
struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.replay_enable.header.type = DMUB_CMD__REPLAY;
|
cmd.replay_enable.header.type = DMUB_CMD__REPLAY;
|
||||||
cmd.replay_enable.data.panel_inst = panel_inst;
|
cmd.replay_enable.data.panel_inst = panel_inst;
|
||||||
|
|
||||||
cmd.replay_enable.header.sub_type = DMUB_CMD__REPLAY_ENABLE;
|
cmd.replay_enable.header.sub_type = DMUB_CMD__REPLAY_ENABLE;
|
||||||
if (enable) {
|
if (enable)
|
||||||
cmd.replay_enable.data.enable = REPLAY_ENABLE;
|
cmd.replay_enable.data.enable = REPLAY_ENABLE;
|
||||||
// hpo stream/link encoder assignments are not static, need to update everytime we try to enable replay
|
else
|
||||||
if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) {
|
|
||||||
for (i = 0; i < MAX_PIPES; i++) {
|
|
||||||
if (res_ctx &&
|
|
||||||
res_ctx->pipe_ctx[i].stream &&
|
|
||||||
res_ctx->pipe_ctx[i].stream->link &&
|
|
||||||
res_ctx->pipe_ctx[i].stream->link == link &&
|
|
||||||
res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
|
|
||||||
pipe_ctx = &res_ctx->pipe_ctx[i];
|
|
||||||
//TODO: refactor for multi edp support
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pipe_ctx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cmd.replay_enable.data.hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
|
|
||||||
cmd.replay_enable.data.hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
cmd.replay_enable.data.enable = REPLAY_DISABLE;
|
cmd.replay_enable.data.enable = REPLAY_DISABLE;
|
||||||
|
|
||||||
cmd.replay_enable.header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_enable_data);
|
cmd.replay_enable.header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_enable_data);
|
||||||
@ -174,17 +149,6 @@ static bool dmub_replay_copy_settings(struct dmub_replay *dmub,
|
|||||||
copy_settings_data->digbe_inst = replay_context->digbe_inst;
|
copy_settings_data->digbe_inst = replay_context->digbe_inst;
|
||||||
copy_settings_data->digfe_inst = replay_context->digfe_inst;
|
copy_settings_data->digfe_inst = replay_context->digfe_inst;
|
||||||
|
|
||||||
if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) {
|
|
||||||
if (pipe_ctx->stream_res.hpo_dp_stream_enc)
|
|
||||||
copy_settings_data->hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
|
|
||||||
else
|
|
||||||
copy_settings_data->hpo_stream_enc_inst = 0;
|
|
||||||
if (pipe_ctx->link_res.hpo_dp_link_enc)
|
|
||||||
copy_settings_data->hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst;
|
|
||||||
else
|
|
||||||
copy_settings_data->hpo_link_enc_inst = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipe_ctx->plane_res.dpp)
|
if (pipe_ctx->plane_res.dpp)
|
||||||
copy_settings_data->dpp_inst = pipe_ctx->plane_res.dpp->inst;
|
copy_settings_data->dpp_inst = pipe_ctx->plane_res.dpp->inst;
|
||||||
else
|
else
|
||||||
@ -247,7 +211,6 @@ static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub,
|
|||||||
pCmd->header.type = DMUB_CMD__REPLAY;
|
pCmd->header.type = DMUB_CMD__REPLAY;
|
||||||
pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL;
|
pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL;
|
||||||
pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data);
|
pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data);
|
||||||
pCmd->replay_set_coasting_vtotal_data.panel_inst = panel_inst;
|
|
||||||
pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF);
|
pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF);
|
||||||
pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16;
|
pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ struct dmub_replay_funcs {
|
|||||||
void (*replay_get_state)(struct dmub_replay *dmub, enum replay_state *state,
|
void (*replay_get_state)(struct dmub_replay *dmub, enum replay_state *state,
|
||||||
uint8_t panel_inst);
|
uint8_t panel_inst);
|
||||||
void (*replay_enable)(struct dmub_replay *dmub, bool enable, bool wait,
|
void (*replay_enable)(struct dmub_replay *dmub, bool enable, bool wait,
|
||||||
uint8_t panel_inst, struct dc_link *link);
|
uint8_t panel_inst);
|
||||||
bool (*replay_copy_settings)(struct dmub_replay *dmub, struct dc_link *link,
|
bool (*replay_copy_settings)(struct dmub_replay *dmub, struct dc_link *link,
|
||||||
struct replay_context *replay_context, uint8_t panel_inst);
|
struct replay_context *replay_context, uint8_t panel_inst);
|
||||||
void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt,
|
void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt,
|
||||||
|
@ -944,7 +944,7 @@ bool edp_set_replay_allow_active(struct dc_link *link, const bool *allow_active,
|
|||||||
// TODO: Handle mux change case if force_static is set
|
// TODO: Handle mux change case if force_static is set
|
||||||
// If force_static is set, just change the replay_allow_active state directly
|
// If force_static is set, just change the replay_allow_active state directly
|
||||||
if (replay != NULL && link->replay_settings.replay_feature_enabled)
|
if (replay != NULL && link->replay_settings.replay_feature_enabled)
|
||||||
replay->funcs->replay_enable(replay, *allow_active, wait, panel_inst, link);
|
replay->funcs->replay_enable(replay, *allow_active, wait, panel_inst);
|
||||||
link->replay_settings.replay_allow_active = *allow_active;
|
link->replay_settings.replay_allow_active = *allow_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4047,14 +4047,6 @@ struct dmub_cmd_replay_copy_settings_data {
|
|||||||
* DIG BE HW instance.
|
* DIG BE HW instance.
|
||||||
*/
|
*/
|
||||||
uint8_t digbe_inst;
|
uint8_t digbe_inst;
|
||||||
/**
|
|
||||||
* @hpo_stream_enc_inst: HPO stream encoder instance
|
|
||||||
*/
|
|
||||||
uint8_t hpo_stream_enc_inst;
|
|
||||||
/**
|
|
||||||
* @hpo_link_enc_inst: HPO link encoder instance
|
|
||||||
*/
|
|
||||||
uint8_t hpo_link_enc_inst;
|
|
||||||
/**
|
/**
|
||||||
* AUX HW instance.
|
* AUX HW instance.
|
||||||
*/
|
*/
|
||||||
@ -4159,18 +4151,6 @@ struct dmub_rb_cmd_replay_enable_data {
|
|||||||
* This does not support HDMI/DP2 for now.
|
* This does not support HDMI/DP2 for now.
|
||||||
*/
|
*/
|
||||||
uint8_t phy_rate;
|
uint8_t phy_rate;
|
||||||
/**
|
|
||||||
* @hpo_stream_enc_inst: HPO stream encoder instance
|
|
||||||
*/
|
|
||||||
uint8_t hpo_stream_enc_inst;
|
|
||||||
/**
|
|
||||||
* @hpo_link_enc_inst: HPO link encoder instance
|
|
||||||
*/
|
|
||||||
uint8_t hpo_link_enc_inst;
|
|
||||||
/**
|
|
||||||
* @pad: Align structure to 4 byte boundary.
|
|
||||||
*/
|
|
||||||
uint8_t pad[2];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,6 +260,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp)
|
|||||||
return MOD_HDCP_STATUS_FAILURE;
|
return MOD_HDCP_STATUS_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!display)
|
||||||
|
return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
|
||||||
|
|
||||||
hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf;
|
hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf;
|
||||||
|
|
||||||
mutex_lock(&psp->hdcp_context.mutex);
|
mutex_lock(&psp->hdcp_context.mutex);
|
||||||
|
@ -1697,9 +1697,11 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
|
|||||||
uint32_t *min_power_limit)
|
uint32_t *min_power_limit)
|
||||||
{
|
{
|
||||||
struct smu_table_context *table_context = &smu->smu_table;
|
struct smu_table_context *table_context = &smu->smu_table;
|
||||||
|
struct smu_14_0_2_powerplay_table *powerplay_table =
|
||||||
|
table_context->power_play_table;
|
||||||
PPTable_t *pptable = table_context->driver_pptable;
|
PPTable_t *pptable = table_context->driver_pptable;
|
||||||
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
|
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
|
||||||
uint32_t power_limit;
|
uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
|
||||||
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||||
|
|
||||||
if (smu_v14_0_get_current_power_limit(smu, &power_limit))
|
if (smu_v14_0_get_current_power_limit(smu, &power_limit))
|
||||||
@ -1712,11 +1714,29 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
|
|||||||
if (default_power_limit)
|
if (default_power_limit)
|
||||||
*default_power_limit = power_limit;
|
*default_power_limit = power_limit;
|
||||||
|
|
||||||
if (max_power_limit)
|
if (powerplay_table) {
|
||||||
*max_power_limit = msg_limit;
|
if (smu->od_enabled &&
|
||||||
|
smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
|
||||||
|
od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt;
|
||||||
|
od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
|
||||||
|
} else if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
|
||||||
|
od_percent_upper = 0;
|
||||||
|
od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (min_power_limit)
|
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||||
*min_power_limit = 0;
|
od_percent_upper, od_percent_lower, power_limit);
|
||||||
|
|
||||||
|
if (max_power_limit) {
|
||||||
|
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||||
|
*max_power_limit /= 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_power_limit) {
|
||||||
|
*min_power_limit = power_limit * (100 + od_percent_lower);
|
||||||
|
*min_power_limit /= 100;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user