summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c')
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c475
1 files changed, 365 insertions, 110 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index e96a12ff2d31..ba7f98a87808 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -104,6 +104,7 @@
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
#include "modules/inc/mod_freesync.h"
+#include "modules/inc/mod_power.h"
#include "modules/power/power_helpers.h"
static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch");
@@ -232,11 +233,11 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev,
static int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
-static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_state *state);
-static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
+static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state);
+static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state);
static int amdgpu_dm_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state);
+ struct drm_atomic_commit *state);
static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
static void handle_hpd_rx_irq(void *param);
@@ -1869,7 +1870,7 @@ static enum dmub_ips_disable_type dm_get_default_ips_mode(
ret = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF;
break;
case IP_VERSION(4, 2, 0):
- ret = DMUB_IPS_DISABLE_ALL;
+ ret = DMUB_IPS_ENABLE;
break;
default:
/* ASICs older than DCN35 do not have IPSs */
@@ -1881,6 +1882,70 @@ static enum dmub_ips_disable_type dm_get_default_ips_mode(
return ret;
}
+static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm)
+{
+ struct mod_power_init_params init_data[MAX_NUM_EDP];
+
+ if (dm->num_of_edps == 0) {
+ drm_dbg_driver(
+ dm->ddev,
+ "amdgpu: No eDP detected, skip initializing power module\n");
+ return 0;
+ }
+
+ /* Initialize all the power module parameters */
+ for (int i = 0; i < dm->num_of_edps; i++) {
+ init_data[i].allow_psr_smu_optimizations =
+ !!(amdgpu_dc_feature_mask & DC_PSR_ALLOW_SMU_OPT);
+ init_data[i].allow_psr_multi_disp_optimizations =
+ !!(amdgpu_dc_feature_mask & DC_PSR_ALLOW_MULTI_DISP_OPT);
+ /* See dm_late_init */
+ init_data[i].backlight_ramping_override = false;
+ init_data[i].backlight_ramping_start = 0xCCCC;
+ init_data[i].backlight_ramping_reduction = 0xCCCCCCCC;
+ init_data[i].def_varibright_level = 0;
+ init_data[i].abm_config_setting = 0;
+ init_data[i].num_backlight_levels = 101;
+ init_data[i].use_nits_based_brightness = false;
+ init_data[i].panel_max_millinits = 0;
+ init_data[i].panel_min_millinits = 0;
+ init_data[i].disable_fractional_pwm =
+ !(amdgpu_dc_feature_mask & DC_DISABLE_FRACTIONAL_PWM_MASK);
+ init_data[i].use_custom_backlight_caps = false;
+ init_data[i].custom_backlight_caps_config_no = 0;
+ init_data[i].use_linear_backlight_curve = false;
+ init_data[i].def_varibright_enable = 0;
+ init_data[i].varibright_level = 0;
+ /*
+ * Power module uses 16-bit backlight levels (0xFFFF max) rather
+ * than 8-bit(0XFF max)
+ */
+ init_data[i].min_backlight_pwm =
+ dm->backlight_caps[i].min_input_signal * 0x101;
+ init_data[i].max_backlight_pwm =
+ dm->backlight_caps[i].max_input_signal * 0x101;
+ init_data[i].min_abm_backlight =
+ dm->backlight_caps[i].min_input_signal * 0x101;
+
+ /* Min backlight level after ABM reduction, Don't allow below 1%
+ * 0xFFFF x 0.01 = 0x28F
+ */
+ init_data[i].min_abm_backlight = (init_data[i].min_abm_backlight < 0x28F) ?
+ 0x28F : init_data[i].min_abm_backlight;
+ }
+
+ dm->power_module = mod_power_create(dm->dc, init_data, dm->num_of_edps);
+ if (!dm->power_module) {
+ drm_err(dm->ddev, "amdgpu: Error allocating memory for power module\n");
+ return -ENOMEM;
+ }
+
+ mod_power_hw_init(dm->power_module);
+ drm_dbg_driver(dm->ddev, "amdgpu: Power module init done\n");
+
+ return 0;
+}
+
static int amdgpu_dm_init(struct amdgpu_device *adev)
{
struct dc_init_data init_data;
@@ -1898,12 +1963,18 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
mutex_init(&adev->dm.dc_lock);
mutex_init(&adev->dm.audio_lock);
+ spin_lock_init(&adev->dm.dmub_lock);
+
if (amdgpu_dm_irq_init(adev)) {
drm_err(adev_to_drm(adev), "failed to initialize DM IRQ support.\n");
goto error;
}
- init_data.asic_id.chip_family = adev->family;
+ /* special handling for early revisions of GC 11.5.4 */
+ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4))
+ init_data.asic_id.chip_family = AMDGPU_FAMILY_GC_11_5_4;
+ else
+ init_data.asic_id.chip_family = adev->family;
init_data.asic_id.pci_revision_id = adev->pdev->revision;
init_data.asic_id.hw_internal_rev = adev->external_rev_id;
@@ -2194,6 +2265,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
goto error;
}
+ if (amdgpu_dm_init_power_module(&adev->dm))
+ goto error;
+
/* create fake encoders for MST */
dm_dp_create_fake_mst_encoders(adev);
@@ -2256,9 +2330,16 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
adev->dm.idle_workqueue = NULL;
}
- /* Disable ISM before dc_destroy() invalidates dm->dc */
+ /*
+ * Disable ISM before dc_destroy() invalidates dm->dc.
+ *
+ * Quiesce workers first without dc_lock (they take dc_lock
+ * themselves, so syncing under it would deadlock), then drive the
+ * FSM back to FULL_POWER_RUNNING under dc_lock.
+ */
+ amdgpu_dm_ism_disable(&adev->dm);
scoped_guard(mutex, &adev->dm.dc_lock)
- amdgpu_dm_ism_disable(&adev->dm);
+ amdgpu_dm_ism_force_full_power(&adev->dm);
amdgpu_dm_destroy_drm_device(&adev->dm);
@@ -2330,6 +2411,10 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
adev->dm.freesync_module = NULL;
}
+ if (adev->dm.power_module) {
+ mod_power_destroy(adev->dm.power_module);
+ adev->dm.power_module = NULL;
+ }
mutex_destroy(&adev->dm.audio_lock);
mutex_destroy(&adev->dm.dc_lock);
mutex_destroy(&adev->dm.dpia_aux_lock);
@@ -3286,9 +3371,14 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
if (amdgpu_in_reset(adev)) {
enum dc_status res;
+ /* Quiesce ISM workers before taking dc_lock (workers take
+ * dc_lock themselves; syncing under it would deadlock).
+ */
+ amdgpu_dm_ism_disable(dm);
+
mutex_lock(&dm->dc_lock);
- amdgpu_dm_ism_disable(dm);
+ amdgpu_dm_ism_force_full_power(dm);
dc_allow_idle_optimizations(adev->dm.dc, false);
dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state);
@@ -3322,8 +3412,13 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
amdgpu_dm_irq_suspend(adev);
+ /*
+ * Quiesce ISM workers before taking dc_lock (workers take dc_lock
+ * themselves; syncing under it would deadlock).
+ */
+ amdgpu_dm_ism_disable(dm);
scoped_guard(mutex, &dm->dc_lock)
- amdgpu_dm_ism_disable(dm);
+ amdgpu_dm_ism_force_full_power(dm);
hpd_rx_irq_work_suspend(dm);
@@ -3338,7 +3433,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
}
struct drm_connector *
-amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
+amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state,
struct drm_crtc *crtc)
{
u32 i;
@@ -4902,7 +4997,7 @@ static int register_outbox_irq_handlers(struct amdgpu_device *adev)
*
* This should only be called during atomic check.
*/
-int dm_atomic_get_state(struct drm_atomic_state *state,
+int dm_atomic_get_state(struct drm_atomic_commit *state,
struct dm_atomic_state **dm_state)
{
struct drm_device *dev = state->dev;
@@ -4923,7 +5018,7 @@ int dm_atomic_get_state(struct drm_atomic_state *state,
}
static struct dm_atomic_state *
-dm_atomic_get_new_state(struct drm_atomic_state *state)
+dm_atomic_get_new_state(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
@@ -5050,8 +5145,8 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
#define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50
-static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
- int bl_idx)
+void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
+ int bl_idx)
{
struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[bl_idx];
@@ -5213,15 +5308,34 @@ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *cap
max - min);
}
+static struct dc_stream_state *dm_find_stream_with_link(
+ struct amdgpu_display_manager *dm,
+ struct dc_link *link)
+{
+ struct dc_state *cur_dc_state = dm->dc->current_state;
+ struct dc_stream_state *stream = NULL;
+ int i;
+
+ for (i = 0; i < cur_dc_state->stream_count; i++) {
+ stream = cur_dc_state->streams[i];
+ if (stream->link == link)
+ return stream;
+ }
+
+ return NULL;
+}
+
static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
int bl_idx,
u32 user_brightness)
{
struct amdgpu_dm_backlight_caps *caps;
struct dc_link *link;
- u32 brightness;
- bool rc, reallow_idle = false;
+ u32 brightness = 0;
+ bool rc = false, reallow_idle = false;
struct drm_connector *connector;
+ struct dc_stream_state *stream;
+ unsigned int min, max;
list_for_each_entry(connector, &dm->ddev->mode_config.connector_list, head) {
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
@@ -5251,13 +5365,6 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
if (caps->brightness_mask)
brightness |= caps->brightness_mask;
- /* Change brightness based on AUX property */
- mutex_lock(&dm->dc_lock);
- if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
- dc_allow_idle_optimizations(dm->dc, false);
- reallow_idle = true;
- }
-
if (trace_amdgpu_dm_brightness_enabled()) {
trace_amdgpu_dm_brightness(__builtin_return_address(0),
user_brightness,
@@ -5266,22 +5373,45 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
power_supply_is_system_supplied() > 0);
}
- if (caps->aux_support) {
- rc = dc_link_set_backlight_level_nits(link, true, brightness,
- AUX_BL_DEFAULT_TRANSITION_TIME_MS);
- if (!rc)
- DRM_DEBUG("DM: Failed to update backlight via AUX on eDP[%d]\n", bl_idx);
- } else {
- struct set_backlight_level_params backlight_level_params = { 0 };
+ stream = dm_find_stream_with_link(dm, link);
+ if (!stream)
+ return;
- backlight_level_params.backlight_pwm_u16_16 = brightness;
- backlight_level_params.transition_time_in_ms = 0;
+ mutex_lock(&dm->dc_lock);
+ if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
+ dc_allow_idle_optimizations(dm->dc, false);
+ reallow_idle = true;
+ }
- rc = dc_link_set_backlight_level(link, &backlight_level_params);
- if (!rc)
- DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", bl_idx);
+ if (caps->aux_support) {
+ rc = mod_power_set_backlight_nits(dm->power_module, stream, brightness,
+ AUX_BL_DEFAULT_TRANSITION_TIME_MS, false, true);
+ } else {
+ /* power module uses millipercent */
+ get_brightness_range(caps, &min, &max);
+ brightness = DIV_ROUND_CLOSEST(brightness * 100, (max - min)) * 1000;
+ rc = mod_power_set_backlight_percent(dm->power_module, stream,
+ brightness, 0, false);
}
+ /*
+ * Some kms clients create a ramped backlight transition effect
+ * by rapidly changing the backlight. Yet we must wait on dmcub
+ * fw to exit psr/replay before programming backlight. To
+ * prevent lag, keep disable psr/replay and let the next atomic
+ * flip clear the event.
+ *
+ * ToDo: use ISM to handle rapidly backlight change
+ *
+ * Rapidly backlight change is similar to rapidly cursor events,
+ * which is now handled by ISM. ISM can delay the event until system
+ * is really idle, so we may use ISM to handle backlight change as well.
+ */
+ amdgpu_dm_psr_set_event(dm, stream, true,
+ psr_event_hw_programming, true);
+ amdgpu_dm_replay_set_event(dm, stream, true,
+ replay_event_hw_programming, true);
+
if (dm->dc->caps.ips_support && reallow_idle)
dc_allow_idle_optimizations(dm->dc, true);
@@ -5499,6 +5629,8 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm,
static void amdgpu_set_panel_orientation(struct drm_connector *connector);
+
+
/*
* In this architecture, the association
* connector -> encoder -> crtc
@@ -5740,7 +5872,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
psr_feature_enabled = false;
if (psr_feature_enabled) {
- amdgpu_dm_set_psr_caps(link);
+ amdgpu_dm_set_psr_caps(link, aconnector);
drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n",
aconnector->base.name,
link->psr_settings.psr_feature_enabled,
@@ -8366,7 +8498,7 @@ static int fill_hdr_info_packet(const struct drm_connector_state *state,
static int
amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_connector_state *new_con_state =
drm_atomic_get_new_connector_state(state, conn);
@@ -8488,7 +8620,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
- struct drm_atomic_state *state = crtc_state->state;
+ struct drm_atomic_commit *state = crtc_state->state;
struct drm_connector *connector = conn_state->connector;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state);
@@ -8560,7 +8692,7 @@ const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
.atomic_check = dm_encoder_helper_atomic_check
};
-static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
+static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state,
struct dc_state *dc_state,
struct dsc_mst_fairness_vars *vars)
{
@@ -9404,9 +9536,21 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
if (acrtc_state) {
timing = &acrtc_state->stream->timing;
- if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
- IP_VERSION(3, 5, 0) ||
- !(adev->flags & AMD_IS_APU)) {
+ if (amdgpu_ip_version(adev, DCE_HWIP, 0) >=
+ IP_VERSION(3, 2, 0) &&
+ !(adev->flags & AMD_IS_APU)) {
+ /*
+ * DGPUs NV3x and newer that support idle optimizations
+ * experience intermittent flip-done timeouts on cursor
+ * updates. Restore 5s offdelay behavior for now.
+ *
+ * Discussion on the issue:
+ * https://lore.kernel.org/amd-gfx/20260217191632.1243826-1-sysdadmin@m1k.cloud/
+ */
+ config.offdelay_ms = 5000;
+ config.disable_immediate = false;
+ } else if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
+ IP_VERSION(3, 5, 0)) {
/*
* Older HW and DGPU have issues with instant off;
* use a 2 frame offdelay.
@@ -9792,7 +9936,8 @@ static void update_stream_irq_parameters(
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
-static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state,
+static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
+ struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state)
{
bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
@@ -9811,6 +9956,14 @@ static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state,
WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0);
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n",
__func__, new_state->base.crtc->base.id);
+
+ scoped_guard(mutex, &dm->dc_lock) {
+ dc_exit_ips_for_hw_access(dm->dc);
+ amdgpu_dm_psr_set_event(dm, new_state->stream, true,
+ psr_event_vrr_transition, true);
+ amdgpu_dm_replay_set_event(dm, new_state->stream, true,
+ replay_event_vrr, true);
+ }
} else if (old_vrr_active && !new_vrr_active) {
/* Transition VRR active -> inactive:
* Allow vblank irq disable again for fixed refresh rate.
@@ -9819,10 +9972,18 @@ static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state,
drm_crtc_vblank_put(new_state->base.crtc);
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n",
__func__, new_state->base.crtc->base.id);
+
+ scoped_guard(mutex, &dm->dc_lock) {
+ dc_exit_ips_for_hw_access(dm->dc);
+ amdgpu_dm_psr_set_event(dm, new_state->stream, false,
+ psr_event_vrr_transition, false);
+ amdgpu_dm_replay_set_event(dm, new_state->stream, false,
+ replay_event_vrr, false);
+ }
}
}
-static void amdgpu_dm_commit_cursors(struct drm_atomic_state *state)
+static void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state)
{
struct drm_plane *plane;
struct drm_plane_state *old_plane_state;
@@ -9916,7 +10077,8 @@ static void amdgpu_dm_update_cursor(struct drm_plane *plane,
}
}
-static void amdgpu_dm_enable_self_refresh(struct amdgpu_crtc *acrtc_attach,
+static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
+ struct amdgpu_crtc *acrtc_attach,
const struct dm_crtc_state *acrtc_state,
const u64 current_ts)
{
@@ -9924,20 +10086,10 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_crtc *acrtc_attach,
struct replay_settings *pr = &acrtc_state->stream->link->replay_settings;
struct amdgpu_dm_connector *aconn =
(struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context;
- bool vrr_active = amdgpu_dm_crtc_vrr_active(acrtc_state);
-
- if (acrtc_state->update_type > UPDATE_TYPE_FAST) {
- if (pr->config.replay_supported && !pr->replay_feature_enabled)
- amdgpu_dm_link_setup_replay(acrtc_state->stream->link, aconn);
- else if (psr->psr_version != DC_PSR_VERSION_UNSUPPORTED &&
- !psr->psr_feature_enabled)
- if (!aconn->disallow_edp_enter_psr)
- amdgpu_dm_link_setup_psr(acrtc_state->stream);
- }
/* Decrement skip count when SR is enabled and we're doing fast updates. */
if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
- (psr->psr_feature_enabled || pr->config.replay_supported)) {
+ (psr->psr_feature_enabled || pr->replay_feature_enabled)) {
if (aconn->sr_skip_count > 0)
aconn->sr_skip_count--;
@@ -9952,24 +10104,20 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_crtc *acrtc_attach,
* of update events.
* See `amdgpu_dm_crtc_vblank_control_worker()`.
*/
- if (!vrr_active &&
- acrtc_attach->dm_irq_params.allow_sr_entry &&
-#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
- !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
-#endif
- (current_ts - psr->psr_dirty_rects_change_timestamp_ns) > 500000000) {
- if (pr->replay_feature_enabled && !pr->replay_allow_active)
- amdgpu_dm_replay_enable(acrtc_state->stream, true);
- if (psr->psr_version == DC_PSR_VERSION_SU_1 &&
- !psr->psr_allow_active && !aconn->disallow_edp_enter_psr)
- amdgpu_dm_psr_enable(acrtc_state->stream);
+ if (acrtc_attach->dm_irq_params.allow_sr_entry &&
+ (current_ts - psr->psr_dirty_rects_change_timestamp_ns) > 500000000) {
+ amdgpu_dm_psr_set_event(dm, acrtc_state->stream, false,
+ psr_event_hw_programming, false);
+
+ amdgpu_dm_replay_set_event(dm, acrtc_state->stream, false,
+ replay_event_hw_programming, false);
}
} else {
acrtc_attach->dm_irq_params.allow_sr_entry = false;
}
}
-static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
struct drm_device *dev,
struct amdgpu_display_manager *dm,
struct drm_crtc *pcrtc,
@@ -10124,15 +10272,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
*/
if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 &&
acrtc_attach->dm_irq_params.allow_sr_entry &&
-#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
- !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
-#endif
dirty_rects_changed) {
mutex_lock(&dm->dc_lock);
acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns =
timestamp_ns;
- if (acrtc_state->stream->link->psr_settings.psr_allow_active)
- amdgpu_dm_psr_disable(acrtc_state->stream, true);
+ dc_exit_ips_for_hw_access(dm->dc);
+ amdgpu_dm_psr_set_event(dm, acrtc_state->stream, true,
+ psr_event_hw_programming, true);
mutex_unlock(&dm->dc_lock);
}
}
@@ -10297,15 +10443,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
bundle->stream_update.abm_level = &acrtc_state->abm_level;
- mutex_lock(&dm->dc_lock);
- if ((acrtc_state->update_type > UPDATE_TYPE_FAST) || vrr_active) {
- if (acrtc_state->stream->link->replay_settings.replay_allow_active)
- amdgpu_dm_replay_disable(acrtc_state->stream);
- if (acrtc_state->stream->link->psr_settings.psr_allow_active)
- amdgpu_dm_psr_disable(acrtc_state->stream, true);
- }
- mutex_unlock(&dm->dc_lock);
-
/*
* If FreeSync state on the stream has changed then we need to
* re-adjust the min/max bounds now that DC doesn't handle this
@@ -10343,8 +10480,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (dm_old_crtc_state->active_planes != acrtc_state->active_planes)
dm_update_pflip_irq_state(drm_to_adev(dev),
acrtc_attach);
-
- amdgpu_dm_enable_self_refresh(acrtc_attach, acrtc_state, timestamp_ns);
+ amdgpu_dm_enable_self_refresh(dm, acrtc_attach, acrtc_state,
+ timestamp_ns);
mutex_unlock(&dm->dc_lock);
}
@@ -10363,7 +10500,7 @@ cleanup:
}
static void amdgpu_dm_commit_audio(struct drm_device *dev,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_dm_connector *aconnector;
@@ -10463,7 +10600,118 @@ static void dm_clear_writeback(struct amdgpu_display_manager *dm,
dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
}
-static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
+/**
+ * amdgpu_dm_mod_power_update_streams - update mod_power stream state on modeset
+ * @state: the drm atomic state
+ * @dm: the display manager to update mod_power on
+ *
+ * Notify mod_power of stream changes on modeset events, and disable PSR/Replay
+ * in preparation for hardware programming. See also
+ * amdgpu_dm_mod_power_setup_streams() for post-modeset mod_power setup.
+ */
+static void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *state,
+ struct amdgpu_display_manager *dm)
+{
+ struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_crtc *crtc;
+ int i = 0;
+
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ continue;
+
+ /*
+ * Update mod_power on modeset event in preparation for hw
+ * programming. Always use the old stream, since it would have
+ * been previously added to mod_power. If old stream is null (on
+ * crtc enable, for example), mod_power will no-op, which is the
+ * desried behavior.
+ */
+ if (old_crtc_state->active) {
+ scoped_guard(mutex, &dm->dc_lock) {
+ dc_exit_ips_for_hw_access(dm->dc);
+ amdgpu_dm_psr_set_event(dm, dm_old_crtc_state->stream, true,
+ psr_event_hw_programming, true);
+ amdgpu_dm_replay_set_event(dm, dm_old_crtc_state->stream, true,
+ replay_event_hw_programming, true);
+ amdgpu_dm_replay_set_event(dm, dm_old_crtc_state->stream, false,
+ replay_event_general_ui, false);
+ }
+ }
+
+ if (new_crtc_state->active) {
+ aconnector = (struct amdgpu_dm_connector *)
+ dm_new_crtc_state->stream->dm_stream_context;
+ if (old_crtc_state->active) {
+ mod_power_replace_stream(dm->power_module,
+ dm_old_crtc_state->stream,
+ dm_new_crtc_state->stream,
+ &aconnector->psr_caps);
+ } else {
+ mod_power_add_stream(dm->power_module,
+ dm_new_crtc_state->stream,
+ &aconnector->psr_caps);
+ }
+ } else if (old_crtc_state->active) {
+ mod_power_remove_stream(dm->power_module,
+ dm_old_crtc_state->stream);
+ }
+ }
+}
+
+/**
+ * amdgpu_dm_mod_power_setup_streams - setup mod_power stream state post modeset
+ * @state: the drm atomic state
+ * @dm: the display manager to update mod_power on
+ *
+ * Notify mod_power of mode_change. This needs to be done after dc_stream
+ * updates have been committed, and VRR parameters have been updated.
+ */
+static void amdgpu_dm_mod_power_setup_streams(struct drm_atomic_commit *state,
+ struct amdgpu_display_manager *dm)
+{
+ struct dm_crtc_state *dm_new_crtc_state;
+ struct drm_crtc_state *new_crtc_state;
+ struct amdgpu_crtc *acrtc;
+ struct drm_crtc *crtc;
+ int i = 0;
+
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ acrtc = to_amdgpu_crtc(crtc);
+
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ continue;
+
+ if (new_crtc_state->active) {
+ amdgpu_dm_link_setup_replay(dm_new_crtc_state->stream,
+ &acrtc->dm_irq_params.vrr_params);
+ mod_power_notify_mode_change(dm->power_module,
+ dm_new_crtc_state->stream,
+ false);
+
+ /*
+ * Block PSR / Replay on the new stream until display settles post-modeset.
+ * These events will be cleared by amdgpu_dm_enable_self_refresh() once
+ * allow_sr_entry becomes true.
+ */
+ amdgpu_dm_psr_set_event(dm, dm_new_crtc_state->stream, true,
+ psr_event_hw_programming, true);
+
+ amdgpu_dm_replay_set_event(dm, dm_new_crtc_state->stream, true,
+ replay_event_hw_programming | replay_event_general_ui,
+ true);
+ }
+ }
+
+}
+
+static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
struct dc_state *dc_state)
{
struct drm_device *dev = state->dev;
@@ -10506,6 +10754,8 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
acrtc->wb_enabled = false;
}
+ amdgpu_dm_mod_power_update_streams(state, dm);
+
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
@@ -10610,13 +10860,10 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
}
} /* for_each_crtc_in_state() */
- /* if there mode set or reset, disable eDP PSR, Replay */
+ /* if there mode set or reset, flush vblank work queue */
if (mode_set_reset_required) {
if (dm->vblank_control_workqueue)
flush_workqueue(dm->vblank_control_workqueue);
-
- amdgpu_dm_replay_disable_all(dm);
- amdgpu_dm_psr_disable_all(dm);
}
dm_enable_per_frame_crtc_master_sync(dc_state);
@@ -10763,7 +11010,7 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm,
drm_writeback_queue_job(wb_conn, new_con_state);
}
-static void amdgpu_dm_update_hdcp(struct drm_atomic_state *state)
+static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
{
struct drm_connector_state *old_con_state, *new_con_state;
struct drm_device *dev = state->dev;
@@ -10878,7 +11125,7 @@ static void amdgpu_dm_update_hdcp(struct drm_atomic_state *state)
}
}
-static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_state *state)
+static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
@@ -10919,7 +11166,7 @@ static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_state *state)
* programming the hardware. Any failures here implies a hardware failure, since
* atomic check should have filtered anything non-kosher.
*/
-static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
@@ -11089,7 +11336,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
manage_dm_interrupts(adev, acrtc, dm_new_crtc_state);
}
/* Handle vrr on->off / off->on transitions */
- amdgpu_dm_handle_vrr_transition(dm_old_crtc_state, dm_new_crtc_state);
+ amdgpu_dm_handle_vrr_transition(dm, dm_old_crtc_state, dm_new_crtc_state);
#ifdef CONFIG_DEBUG_FS
if (new_crtc_state->active &&
@@ -11127,6 +11374,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
#endif
}
+ amdgpu_dm_mod_power_setup_streams(state, dm);
+
for_each_new_crtc_in_state(state, crtc, new_crtc_state, j)
if (new_crtc_state->async_flip)
wait_for_vblank = false;
@@ -11224,7 +11473,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
{
int ret = 0;
struct drm_device *ddev = connector->dev;
- struct drm_atomic_state *state = drm_atomic_state_alloc(ddev);
+ struct drm_atomic_commit *state = drm_atomic_commit_alloc(ddev);
struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
struct drm_plane *plane = disconnected_acrtc->base.primary;
struct drm_connector_state *conn_state;
@@ -11239,7 +11488,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
/* Construct an atomic state to restore previous display setting */
/*
- * Attach connectors to drm_atomic_state
+ * Attach connectors to drm_atomic_commit
*/
conn_state = drm_atomic_get_connector_state(state, connector);
@@ -11249,7 +11498,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
goto out;
}
- /* Attach crtc to drm_atomic_state*/
+ /* Attach crtc to drm_atomic_commit*/
crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
/* Check for error in getting crtc state */
@@ -11261,7 +11510,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
/* force a restore */
crtc_state->mode_changed = true;
- /* Attach plane to drm_atomic_state */
+ /* Attach plane to drm_atomic_commit */
plane_state = drm_atomic_get_plane_state(state, plane);
/* Check for error in getting plane state */
@@ -11274,7 +11523,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
ret = drm_atomic_commit(state);
out:
- drm_atomic_state_put(state);
+ drm_atomic_commit_put(state);
if (ret)
drm_err(ddev, "Restoring old state failed with %i\n", ret);
@@ -11323,7 +11572,7 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
* Waits for completion of all non blocking commits.
*/
static int do_aquire_global_lock(struct drm_device *dev,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc *crtc;
struct drm_crtc_commit *commit;
@@ -11468,7 +11717,7 @@ static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
}
static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state,
struct drm_crtc_state *new_crtc_state,
@@ -11742,7 +11991,7 @@ fail:
return ret;
}
-static bool should_reset_plane(struct drm_atomic_state *state,
+static bool should_reset_plane(struct drm_atomic_commit *state,
struct drm_plane *plane,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state)
@@ -12000,7 +12249,7 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc,
return 0;
}
-static bool dm_should_update_native_cursor(struct drm_atomic_state *state,
+static bool dm_should_update_native_cursor(struct drm_atomic_commit *state,
struct drm_crtc *old_plane_crtc,
struct drm_crtc *new_plane_crtc,
bool enable)
@@ -12030,7 +12279,7 @@ static bool dm_should_update_native_cursor(struct drm_atomic_state *state,
}
static int dm_update_plane_state(struct dc *dc,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
struct drm_plane *plane,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state,
@@ -12238,7 +12487,7 @@ dm_get_plane_scale(struct drm_plane_state *plane_state,
* indefinitely.
*/
static inline struct __drm_planes_state *__get_next_zpos(
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
struct __drm_planes_state *prev)
{
unsigned int highest_zpos = 0, prev_zpos = 256;
@@ -12288,7 +12537,7 @@ static inline struct __drm_planes_state *__get_next_zpos(
(old_plane_state) = __i->old_state, \
(new_plane_state) = __i->new_state, 1))
-static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc)
+static int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state, struct drm_crtc *crtc)
{
struct drm_connector *connector;
struct drm_connector_state *conn_state, *old_conn_state;
@@ -12347,7 +12596,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
*
* Return: true if the pipeline modifies pixels, false otherwise.
*/
-static bool dm_plane_color_pipeline_active(struct drm_atomic_state *state,
+static bool dm_plane_color_pipeline_active(struct drm_atomic_commit *state,
struct drm_plane *plane,
bool use_old)
{
@@ -12387,7 +12636,7 @@ static bool dm_plane_color_pipeline_active(struct drm_atomic_state *state,
* failed.
*/
static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
struct dm_crtc_state *dm_crtc_state,
enum amdgpu_dm_cursor_mode *cursor_mode)
{
@@ -12526,7 +12775,7 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
}
static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
struct drm_crtc_state *crtc_state)
{
struct drm_plane *plane;
@@ -12575,7 +12824,7 @@ static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
* Return: -Error code if validation failed.
*/
static int amdgpu_dm_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct amdgpu_device *adev = drm_to_adev(dev);
struct dm_atomic_state *dm_state = NULL;
@@ -13685,11 +13934,17 @@ int amdgpu_dm_process_dmub_set_config_sync(
bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
{
+ struct amdgpu_device *adev = ctx->driver_context;
+
+ guard(spinlock_irqsave)(&adev->dm.dmub_lock);
return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
}
bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
{
+ struct amdgpu_device *adev = ctx->driver_context;
+
+ guard(spinlock_irqsave)(&adev->dm.dmub_lock);
return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type);
}