Commit 460ea5b3 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher

drm/amd/display: Add debug prints for IPS testing

[WHY]
To log commit states and when we transition in/out of allow and idle
states and the caller.

[HOW]
Add a new logging helper and wrap idle optimization calls to receive
the caller.
Reviewed-by: default avatarDuncan Ma <duncan.ma@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 2f72e02f
......@@ -4874,11 +4874,15 @@ bool dc_set_replay_allow_active(struct dc *dc, bool active)
return true;
}
void dc_allow_idle_optimizations(struct dc *dc, bool allow)
void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const *caller_name)
{
if (dc->debug.disable_idle_power_optimizations)
return;
if (allow != dc->idle_optimizations_allowed)
DC_LOG_IPS("%s: allow_idle old=%d new=%d (caller=%s)\n", __func__,
dc->idle_optimizations_allowed, allow, caller_name);
if (dc->caps.ips_support && (dc->config.disable_ips == DMUB_IPS_DISABLE_ALL))
return;
......@@ -4893,10 +4897,10 @@ void dc_allow_idle_optimizations(struct dc *dc, bool allow)
dc->idle_optimizations_allowed = allow;
}
void dc_exit_ips_for_hw_access(struct dc *dc)
void dc_exit_ips_for_hw_access_internal(struct dc *dc, const char *caller_name)
{
if (dc->caps.ips_support)
dc_allow_idle_optimizations(dc, false);
dc_allow_idle_optimizations_internal(dc, false, caller_name);
}
bool dc_dmub_is_ips_idle_state(struct dc *dc)
......
......@@ -2339,8 +2339,11 @@ void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_
bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc, struct dc_plane_state *plane,
struct dc_cursor_attributes *cursor_attr);
void dc_allow_idle_optimizations(struct dc *dc, bool allow);
void dc_exit_ips_for_hw_access(struct dc *dc);
#define dc_allow_idle_optimizations(dc, allow) dc_allow_idle_optimizations_internal(dc, allow, __func__)
#define dc_exit_ips_for_hw_access(dc) dc_exit_ips_for_hw_access_internal(dc, __func__)
void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, const char *caller_name);
void dc_exit_ips_for_hw_access_internal(struct dc *dc, const char *caller_name);
bool dc_dmub_is_ips_idle_state(struct dc *dc);
/* set min and max memory clock to lowest and highest DPM level, respectively */
......
......@@ -910,6 +910,8 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
return;
}
DC_LOG_ERROR("%s: DMCUB error - collecting diagnostic data\n", __func__);
if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) {
DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__);
return;
......@@ -1201,6 +1203,7 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait)
static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
{
volatile const struct dmub_shared_state_ips_fw *ips_fw;
struct dc_dmub_srv *dc_dmub_srv;
union dmub_rb_cmd cmd = {0};
......@@ -1211,6 +1214,7 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
return;
dc_dmub_srv = dc->ctx->dmub_srv;
ips_fw = &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw;
memset(&cmd, 0, sizeof(cmd));
cmd.idle_opt_notify_idle.header.type = DMUB_CMD__IDLE_OPT;
......@@ -1226,6 +1230,12 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
&dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_DRIVER].data.ips_driver;
union dmub_shared_state_ips_driver_signals new_signals;
DC_LOG_IPS(
"%s wait idle (ips1_commit=%d ips2_commit=%d)",
__func__,
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
memset(&new_signals, 0, sizeof(new_signals));
......@@ -1250,6 +1260,13 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
ips_driver->signals = new_signals;
}
DC_LOG_IPS(
"%s send allow_idle=%d (ips1_commit=%d ips2_commit=%d)",
__func__,
allow_idle,
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
/* NOTE: This does not use the "wake" interface since this is part of the wake path. */
/* We also do not perform a wait since DMCUB could enter idle after the notification. */
dm_execute_dmub_cmd(dc->ctx, &cmd, allow_idle ? DM_DMUB_WAIT_TYPE_NO_WAIT : DM_DMUB_WAIT_TYPE_WAIT);
......@@ -1276,38 +1293,92 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
ips_driver->signals.all = 0;
DC_LOG_IPS(
"%s check (allow_ips1=%d allow_ips2=%d) (ips1_commit=%d ips2_commit=%d)",
__func__,
ips_driver->signals.bits.allow_ips1,
ips_driver->signals.bits.allow_ips2,
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
if (prev_driver_signals.bits.allow_ips2) {
DC_LOG_IPS(
"wait IPS2 eval (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
udelay(dc->debug.ips2_eval_delay_us);
if (ips_fw->signals.bits.ips2_commit) {
DC_LOG_IPS(
"exit IPS2 #1 (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
// Tell PMFW to exit low power state
dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
DC_LOG_IPS(
"wait IPS2 entry delay (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
// Wait for IPS2 entry upper bound
udelay(dc->debug.ips2_entry_delay_us);
DC_LOG_IPS(
"exit IPS2 #2 (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
DC_LOG_IPS(
"wait IPS2 commit clear (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
while (ips_fw->signals.bits.ips2_commit)
udelay(1);
DC_LOG_IPS(
"wait hw_pwr_up (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
ASSERT(0);
DC_LOG_IPS(
"resync inbox1 (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
dmub_srv_sync_inbox1(dc->ctx->dmub_srv->dmub);
}
}
dc_dmub_srv_notify_idle(dc, false);
if (prev_driver_signals.bits.allow_ips1) {
DC_LOG_IPS(
"wait for IPS1 commit clear (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
while (ips_fw->signals.bits.ips1_commit)
udelay(1);
DC_LOG_IPS(
"wait for IPS1 commit clear done (ips1_commit=%d ips2_commit=%d)",
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
}
}
if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
ASSERT(0);
DC_LOG_IPS("%s exited", __func__);
}
void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state powerState)
......@@ -1335,6 +1406,8 @@ void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_
if (dc_dmub_srv->idle_allowed == allow_idle)
return;
DC_LOG_IPS("%s state change: old=%d new=%d", __func__, dc_dmub_srv->idle_allowed, allow_idle);
/*
* Entering a low power state requires a driver notification.
* Powering up the hardware requires notifying PMFW and DMCUB.
......
......@@ -64,6 +64,7 @@
#define DC_LOG_DWB(...) drm_dbg((DC_LOGGER)->dev, __VA_ARGS__)
#define DC_LOG_DP2(...) drm_dbg_dp((DC_LOGGER)->dev, __VA_ARGS__)
#define DC_LOG_AUTO_DPM_TEST(...) pr_debug("[AutoDPMTest]: "__VA_ARGS__)
#define DC_LOG_IPS(...) pr_debug("[IPS]: "__VA_ARGS__)
struct dc_log_buffer_ctx {
char *buf;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment