mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-18 06:33:43 -04:00
Merge tag 'amd-drm-next-6.19-2025-10-29' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-6.19-2025-10-29: amdgpu: - VPE idle handler fix - Re-enable DM idle optimizations - DCN3.0 fix - SMU fix - Powerplay fixes for fiji/iceland - License copy-pasta fixes - HDP eDP panel fix - Vblank fix - RAS fixes - SR-IOV updates - SMU 13 VCN reset fix - DMUB fixes - DC frame limit fix - Additional DC underflow logging - DCN 3.1.5 fixes - DC Analog encoders support - Enable DC on bonaire by default - UserQ fixes - Remove redundant pm_runtime_mark_last_busy() calls amdkfd: - Process cleanup fix - Misc fixes radeon: - devm migration fixes - Remove redundant pm_runtime_mark_last_busy() calls UAPI - Add ABM KMS property Proposed kwin changes: https://invent.kde.org/plasma/kwin/-/merge_requests/6028 Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20251029205713.9480-1-alexander.deucher@amd.com
This commit is contained in:
@@ -3853,7 +3853,9 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
|
||||
aconnector->connector_id, aconnector->dc_sink, sink);
|
||||
|
||||
guard(mutex)(&dev->mode_config.mutex);
|
||||
/* When polling, DRM has already locked the mutex for us. */
|
||||
if (!drm_kms_helper_is_poll_worker())
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
/*
|
||||
* 1. Update status of the drm connector
|
||||
@@ -3916,6 +3918,10 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
}
|
||||
|
||||
update_subconnector_property(aconnector);
|
||||
|
||||
/* When polling, the mutex will be unlocked for us by DRM. */
|
||||
if (!drm_kms_helper_is_poll_worker())
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
|
||||
@@ -5200,6 +5206,7 @@ static int initialize_plane(struct amdgpu_display_manager *dm,
|
||||
static void setup_backlight_device(struct amdgpu_display_manager *dm,
|
||||
struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
struct amdgpu_dm_backlight_caps *caps;
|
||||
struct dc_link *link = aconnector->dc_link;
|
||||
int bl_idx = dm->num_of_edps;
|
||||
|
||||
@@ -5219,6 +5226,13 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm,
|
||||
dm->num_of_edps++;
|
||||
|
||||
update_connector_ext_caps(aconnector);
|
||||
caps = &dm->backlight_caps[aconnector->bl_idx];
|
||||
|
||||
/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
|
||||
if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
|
||||
drm_object_attach_property(&aconnector->base.base,
|
||||
dm->adev->mode_info.abm_level_property,
|
||||
ABM_SYSFS_CONTROL);
|
||||
}
|
||||
|
||||
static void amdgpu_set_panel_orientation(struct drm_connector *connector);
|
||||
@@ -7218,29 +7232,101 @@ finish:
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dm_connector_poll() - Poll a connector to see if it's connected to a display
|
||||
*
|
||||
* Used for connectors that don't support HPD (hotplug detection)
|
||||
* to periodically checked whether the connector is connected to a display.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
|
||||
{
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct dc_link *link = aconnector->dc_link;
|
||||
enum dc_connection_type conn_type = dc_connection_none;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
/* When we determined the connection using DAC load detection,
|
||||
* do NOT poll the connector do detect disconnect because
|
||||
* that would run DAC load detection again which can cause
|
||||
* visible visual glitches.
|
||||
*
|
||||
* Only allow to poll such a connector again when forcing.
|
||||
*/
|
||||
if (!force && link->local_sink && link->type == dc_connection_dac_load)
|
||||
return connector->status;
|
||||
|
||||
mutex_lock(&aconnector->hpd_lock);
|
||||
|
||||
if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) &&
|
||||
conn_type != dc_connection_none) {
|
||||
mutex_lock(&adev->dm.dc_lock);
|
||||
|
||||
/* Only call full link detection when a sink isn't created yet,
|
||||
* ie. just when the display is plugged in, otherwise we risk flickering.
|
||||
*/
|
||||
if (link->local_sink ||
|
||||
dc_link_detect(link, DETECT_REASON_HPD))
|
||||
status = connector_status_connected;
|
||||
|
||||
mutex_unlock(&adev->dm.dc_lock);
|
||||
}
|
||||
|
||||
if (connector->status != status) {
|
||||
if (status == connector_status_disconnected) {
|
||||
if (link->local_sink)
|
||||
dc_sink_release(link->local_sink);
|
||||
|
||||
link->local_sink = NULL;
|
||||
link->dpcd_sink_count = 0;
|
||||
link->type = dc_connection_none;
|
||||
}
|
||||
|
||||
amdgpu_dm_update_connector_after_detect(aconnector);
|
||||
}
|
||||
|
||||
mutex_unlock(&aconnector->hpd_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
|
||||
*
|
||||
* A connector is considered connected when it has a sink that is not NULL.
|
||||
* For connectors that support HPD (hotplug detection), the connection is
|
||||
* handled in the HPD interrupt.
|
||||
* For connectors that may not support HPD, such as analog connectors,
|
||||
* DRM will call this function repeatedly to poll them.
|
||||
*
|
||||
* Notes:
|
||||
* 1. This interface is NOT called in context of HPD irq.
|
||||
* 2. This interface *is called* in context of user-mode ioctl. Which
|
||||
* makes it a bad place for *any* MST-related activity.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
bool connected;
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* 1. This interface is NOT called in context of HPD irq.
|
||||
* 2. This interface *is called* in context of user-mode ioctl. Which
|
||||
* makes it a bad place for *any* MST-related activity.
|
||||
*/
|
||||
|
||||
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED &&
|
||||
!aconnector->fake_enable)
|
||||
connected = (aconnector->dc_sink != NULL);
|
||||
else
|
||||
connected = (aconnector->base.force == DRM_FORCE_ON ||
|
||||
aconnector->base.force == DRM_FORCE_ON_DIGITAL);
|
||||
|
||||
update_subconnector_property(aconnector);
|
||||
|
||||
return (connected ? connector_status_connected :
|
||||
if (aconnector->base.force == DRM_FORCE_ON ||
|
||||
aconnector->base.force == DRM_FORCE_ON_DIGITAL)
|
||||
return connector_status_connected;
|
||||
else if (aconnector->base.force == DRM_FORCE_OFF)
|
||||
return connector_status_disconnected;
|
||||
|
||||
/* Poll analog connectors and only when either
|
||||
* disconnected or connected to an analog display.
|
||||
*/
|
||||
if (drm_kms_helper_is_poll_worker() &&
|
||||
dc_connector_supports_analog(aconnector->dc_link->link_id.id) &&
|
||||
(!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog))
|
||||
return amdgpu_dm_connector_poll(aconnector, force);
|
||||
|
||||
return (aconnector->dc_sink ? connector_status_connected :
|
||||
connector_status_disconnected);
|
||||
}
|
||||
|
||||
@@ -7291,6 +7377,20 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
|
||||
} else if (property == adev->mode_info.underscan_property) {
|
||||
dm_new_state->underscan_enable = val;
|
||||
ret = 0;
|
||||
} else if (property == adev->mode_info.abm_level_property) {
|
||||
switch (val) {
|
||||
case ABM_SYSFS_CONTROL:
|
||||
dm_new_state->abm_sysfs_forbidden = false;
|
||||
break;
|
||||
case ABM_LEVEL_OFF:
|
||||
dm_new_state->abm_sysfs_forbidden = true;
|
||||
dm_new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
|
||||
break;
|
||||
default:
|
||||
dm_new_state->abm_sysfs_forbidden = true;
|
||||
dm_new_state->abm_level = val;
|
||||
};
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -7333,6 +7433,13 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
|
||||
} else if (property == adev->mode_info.underscan_property) {
|
||||
*val = dm_state->underscan_enable;
|
||||
ret = 0;
|
||||
} else if (property == adev->mode_info.abm_level_property) {
|
||||
if (!dm_state->abm_sysfs_forbidden)
|
||||
*val = ABM_SYSFS_CONTROL;
|
||||
else
|
||||
*val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
|
||||
dm_state->abm_level : 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -7385,10 +7492,16 @@ static ssize_t panel_power_savings_store(struct device *device,
|
||||
return -EINVAL;
|
||||
|
||||
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
||||
to_dm_connector_state(connector->state)->abm_level = val ?:
|
||||
ABM_LEVEL_IMMEDIATE_DISABLE;
|
||||
if (to_dm_connector_state(connector->state)->abm_sysfs_forbidden)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
to_dm_connector_state(connector->state)->abm_level = val ?:
|
||||
ABM_LEVEL_IMMEDIATE_DISABLE;
|
||||
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_kms_helper_hotplug_event(dev);
|
||||
|
||||
return count;
|
||||
@@ -8228,7 +8341,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int to_drm_connector_type(enum signal_type st)
|
||||
static int to_drm_connector_type(enum signal_type st, uint32_t connector_id)
|
||||
{
|
||||
switch (st) {
|
||||
case SIGNAL_TYPE_HDMI_TYPE_A:
|
||||
@@ -8244,6 +8357,10 @@ static int to_drm_connector_type(enum signal_type st)
|
||||
return DRM_MODE_CONNECTOR_DisplayPort;
|
||||
case SIGNAL_TYPE_DVI_DUAL_LINK:
|
||||
case SIGNAL_TYPE_DVI_SINGLE_LINK:
|
||||
if (connector_id == CONNECTOR_ID_SINGLE_LINK_DVII ||
|
||||
connector_id == CONNECTOR_ID_DUAL_LINK_DVII)
|
||||
return DRM_MODE_CONNECTOR_DVII;
|
||||
|
||||
return DRM_MODE_CONNECTOR_DVID;
|
||||
case SIGNAL_TYPE_VIRTUAL:
|
||||
return DRM_MODE_CONNECTOR_VIRTUAL;
|
||||
@@ -8295,7 +8412,7 @@ static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
|
||||
|
||||
static struct drm_display_mode *
|
||||
amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
|
||||
char *name,
|
||||
const char *name,
|
||||
int hdisplay, int vdisplay)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
@@ -8317,6 +8434,24 @@ amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
|
||||
|
||||
}
|
||||
|
||||
static const struct amdgpu_dm_mode_size {
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
int w;
|
||||
int h;
|
||||
} common_modes[] = {
|
||||
{ "640x480", 640, 480},
|
||||
{ "800x600", 800, 600},
|
||||
{ "1024x768", 1024, 768},
|
||||
{ "1280x720", 1280, 720},
|
||||
{ "1280x800", 1280, 800},
|
||||
{"1280x1024", 1280, 1024},
|
||||
{ "1440x900", 1440, 900},
|
||||
{"1680x1050", 1680, 1050},
|
||||
{"1600x1200", 1600, 1200},
|
||||
{"1920x1080", 1920, 1080},
|
||||
{"1920x1200", 1920, 1200}
|
||||
};
|
||||
|
||||
static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
@@ -8327,23 +8462,6 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
|
||||
to_amdgpu_dm_connector(connector);
|
||||
int i;
|
||||
int n;
|
||||
struct mode_size {
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
int w;
|
||||
int h;
|
||||
} common_modes[] = {
|
||||
{ "640x480", 640, 480},
|
||||
{ "800x600", 800, 600},
|
||||
{ "1024x768", 1024, 768},
|
||||
{ "1280x720", 1280, 720},
|
||||
{ "1280x800", 1280, 800},
|
||||
{"1280x1024", 1280, 1024},
|
||||
{ "1440x900", 1440, 900},
|
||||
{"1680x1050", 1680, 1050},
|
||||
{"1600x1200", 1600, 1200},
|
||||
{"1920x1080", 1920, 1080},
|
||||
{"1920x1200", 1920, 1200}
|
||||
};
|
||||
|
||||
if ((connector->connector_type != DRM_MODE_CONNECTOR_eDP) &&
|
||||
(connector->connector_type != DRM_MODE_CONNECTOR_LVDS))
|
||||
@@ -8544,6 +8662,10 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect
|
||||
if (!(amdgpu_freesync_vid_mode && drm_edid))
|
||||
return;
|
||||
|
||||
if (!amdgpu_dm_connector->dc_sink || amdgpu_dm_connector->dc_sink->edid_caps.analog ||
|
||||
!dc_supports_vrr(amdgpu_dm_connector->dc_sink->ctx->dce_version))
|
||||
return;
|
||||
|
||||
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
|
||||
amdgpu_dm_connector->num_modes +=
|
||||
add_fs_modes(amdgpu_dm_connector);
|
||||
@@ -8567,6 +8689,15 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
|
||||
if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING)
|
||||
amdgpu_dm_connector->num_modes +=
|
||||
drm_add_modes_noedid(connector, 1920, 1080);
|
||||
|
||||
if (amdgpu_dm_connector->dc_sink->edid_caps.analog) {
|
||||
/* Analog monitor connected by DAC load detection.
|
||||
* Add common modes. It will be up to the user to select one that works.
|
||||
*/
|
||||
for (int i = 0; i < ARRAY_SIZE(common_modes); i++)
|
||||
amdgpu_dm_connector->num_modes += drm_add_modes_noedid(
|
||||
connector, common_modes[i].w, common_modes[i].h);
|
||||
}
|
||||
} else {
|
||||
amdgpu_dm_connector_ddc_get_modes(connector, drm_edid);
|
||||
if (encoder)
|
||||
@@ -8635,6 +8766,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
|
||||
case DRM_MODE_CONNECTOR_DVID:
|
||||
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVII:
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
aconnector->base.polled =
|
||||
DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -8836,7 +8972,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
connector_type = to_drm_connector_type(link->connector_signal);
|
||||
connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id);
|
||||
|
||||
res = drm_connector_init_with_ddc(
|
||||
dm->ddev,
|
||||
|
||||
Reference in New Issue
Block a user