summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2021-07-30 16:48:35 +1000
committerDave Airlie <airlied@redhat.com>2021-07-30 16:48:35 +1000
commit04d505de7f82c8f2daa6139b460b05dc01e354e0 (patch)
treea5b4f62c721cffa1ff4f1625d76e9d8f79a9d0df /drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
parentf1b7996551a40a4ebb551130c83077a0cabcb935 (diff)
parent544dcd74b7093ad4befac99b11d90331aa73348e (diff)
Merge tag 'amd-drm-next-5.15-2021-07-29' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-5.15-2021-07-29: amdgpu: - VCN/JPEG power down sequencing fixes - Various navi pcie link handling fixes - Clockgating fixes - Yellow Carp fixes - Beige Goby fixes - Misc code cleanups - S0ix fixes - SMU i2c bus rework - EEPROM handling rework - PSP ucode handling cleanup - SMU error handling rework - AMD HDMI freesync fixes - USB PD firmware update rework - MMIO based vram access rework - Misc display fixes - Backlight fixes - Add initial Cyan Skillfish support - Overclocking fixes suspend/resume amdkfd: - Sysfs leak fix - Add counters for vm faults and migration - GPUVM TLB optimizations radeon: - Misc fixes Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210730033455.3852-1-alexander.deucher@amd.com
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.c260
1 files changed, 179 insertions, 81 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 d3a2a5ff57e9..986c9d29d686 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -618,6 +618,7 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
}
#endif
+#define DMUB_TRACE_MAX_READ 64
/**
* dm_dmub_outbox1_low_irq() - Handles Outbox interrupt
* @interrupt_params: used for determining the Outbox instance
@@ -625,7 +626,6 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
* Handles the Outbox Interrupt
* event handler.
*/
-#define DMUB_TRACE_MAX_READ 64
static void dm_dmub_outbox1_low_irq(void *interrupt_params)
{
struct dmub_notification notify;
@@ -2412,6 +2412,7 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
static const u8 pre_computed_values[] = {
50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 63, 65, 66, 68, 69,
71, 72, 74, 75, 77, 79, 81, 82, 84, 86, 88, 90, 92, 94, 96, 98};
+ int i;
if (!aconnector || !aconnector->dc_link)
return;
@@ -2423,15 +2424,21 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
conn_base = &aconnector->base;
adev = drm_to_adev(conn_base->dev);
dm = &adev->dm;
- caps = &dm->backlight_caps;
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if (link == dm->backlight_link[i])
+ break;
+ }
+ if (i >= dm->num_of_edps)
+ return;
+ caps = &dm->backlight_caps[i];
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
caps->aux_support = false;
max_cll = conn_base->hdr_sink_metadata.hdmi_type1.max_cll;
min_cll = conn_base->hdr_sink_metadata.hdmi_type1.min_cll;
- if (caps->ext_caps->bits.oled == 1 ||
+ if (caps->ext_caps->bits.oled == 1 /*||
caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
- caps->ext_caps->bits.hdr_aux_backlight_control == 1)
+ caps->ext_caps->bits.hdr_aux_backlight_control == 1*/)
caps->aux_support = true;
if (amdgpu_backlight == 0)
@@ -3423,35 +3430,36 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
-static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm)
+static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
+ int bl_idx)
{
#if defined(CONFIG_ACPI)
struct amdgpu_dm_backlight_caps caps;
memset(&caps, 0, sizeof(caps));
- if (dm->backlight_caps.caps_valid)
+ if (dm->backlight_caps[bl_idx].caps_valid)
return;
amdgpu_acpi_get_backlight_caps(&caps);
if (caps.caps_valid) {
- dm->backlight_caps.caps_valid = true;
+ dm->backlight_caps[bl_idx].caps_valid = true;
if (caps.aux_support)
return;
- dm->backlight_caps.min_input_signal = caps.min_input_signal;
- dm->backlight_caps.max_input_signal = caps.max_input_signal;
+ dm->backlight_caps[bl_idx].min_input_signal = caps.min_input_signal;
+ dm->backlight_caps[bl_idx].max_input_signal = caps.max_input_signal;
} else {
- dm->backlight_caps.min_input_signal =
+ dm->backlight_caps[bl_idx].min_input_signal =
AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- dm->backlight_caps.max_input_signal =
+ dm->backlight_caps[bl_idx].max_input_signal =
AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
}
#else
- if (dm->backlight_caps.aux_support)
+ if (dm->backlight_caps[bl_idx].aux_support)
return;
- dm->backlight_caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- dm->backlight_caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
+ dm->backlight_caps[bl_idx].min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
+ dm->backlight_caps[bl_idx].max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
#endif
}
@@ -3502,41 +3510,31 @@ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *cap
}
static int 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[AMDGPU_DM_MAX_NUM_EDP];
- u32 brightness[AMDGPU_DM_MAX_NUM_EDP];
+ struct dc_link *link;
+ u32 brightness;
bool rc;
- int i;
- amdgpu_dm_update_backlight_caps(dm);
- caps = dm->backlight_caps;
+ amdgpu_dm_update_backlight_caps(dm, bl_idx);
+ caps = dm->backlight_caps[bl_idx];
- for (i = 0; i < dm->num_of_edps; i++) {
- dm->brightness[i] = user_brightness;
- brightness[i] = convert_brightness_from_user(&caps, dm->brightness[i]);
- link[i] = (struct dc_link *)dm->backlight_link[i];
- }
+ dm->brightness[bl_idx] = user_brightness;
+ brightness = convert_brightness_from_user(&caps, dm->brightness[bl_idx]);
+ link = (struct dc_link *)dm->backlight_link[bl_idx];
/* Change brightness based on AUX property */
if (caps.aux_support) {
- for (i = 0; i < dm->num_of_edps; i++) {
- rc = dc_link_set_backlight_level_nits(link[i], true, brightness[i],
- AUX_BL_DEFAULT_TRANSITION_TIME_MS);
- if (!rc) {
- DRM_DEBUG("DM: Failed to update backlight via AUX on eDP[%d]\n", i);
- break;
- }
- }
+ 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 {
- for (i = 0; i < dm->num_of_edps; i++) {
- rc = dc_link_set_backlight_level(dm->backlight_link[i], brightness[i], 0);
- if (!rc) {
- DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", i);
- break;
- }
- }
+ rc = dc_link_set_backlight_level(link, brightness, 0);
+ if (!rc)
+ DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", bl_idx);
}
return rc ? 0 : 1;
@@ -3545,33 +3543,41 @@ static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
{
struct amdgpu_display_manager *dm = bl_get_data(bd);
+ int i;
- amdgpu_dm_backlight_set_level(dm, bd->props.brightness);
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if (bd == dm->backlight_dev[i])
+ break;
+ }
+ if (i >= AMDGPU_DM_MAX_NUM_EDP)
+ i = 0;
+ amdgpu_dm_backlight_set_level(dm, i, bd->props.brightness);
return 0;
}
-static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm)
+static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm,
+ int bl_idx)
{
struct amdgpu_dm_backlight_caps caps;
+ struct dc_link *link = (struct dc_link *)dm->backlight_link[bl_idx];
- amdgpu_dm_update_backlight_caps(dm);
- caps = dm->backlight_caps;
+ amdgpu_dm_update_backlight_caps(dm, bl_idx);
+ caps = dm->backlight_caps[bl_idx];
if (caps.aux_support) {
- struct dc_link *link = (struct dc_link *)dm->backlight_link[0];
u32 avg, peak;
bool rc;
rc = dc_link_get_backlight_level_nits(link, &avg, &peak);
if (!rc)
- return dm->brightness[0];
+ return dm->brightness[bl_idx];
return convert_brightness_to_user(&caps, avg);
} else {
- int ret = dc_link_get_backlight_level(dm->backlight_link[0]);
+ int ret = dc_link_get_backlight_level(link);
if (ret == DC_ERROR_UNEXPECTED)
- return dm->brightness[0];
+ return dm->brightness[bl_idx];
return convert_brightness_to_user(&caps, ret);
}
}
@@ -3579,8 +3585,15 @@ static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm)
static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
{
struct amdgpu_display_manager *dm = bl_get_data(bd);
+ int i;
- return amdgpu_dm_backlight_get_level(dm);
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if (bd == dm->backlight_dev[i])
+ break;
+ }
+ if (i >= AMDGPU_DM_MAX_NUM_EDP)
+ i = 0;
+ return amdgpu_dm_backlight_get_level(dm, i);
}
static const struct backlight_ops amdgpu_dm_backlight_ops = {
@@ -3594,31 +3607,28 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
{
char bl_name[16];
struct backlight_properties props = { 0 };
- int i;
- amdgpu_dm_update_backlight_caps(dm);
- for (i = 0; i < dm->num_of_edps; i++)
- dm->brightness[i] = AMDGPU_MAX_BL_LEVEL;
+ amdgpu_dm_update_backlight_caps(dm, dm->num_of_edps);
+ dm->brightness[dm->num_of_edps] = AMDGPU_MAX_BL_LEVEL;
props.max_brightness = AMDGPU_MAX_BL_LEVEL;
props.brightness = AMDGPU_MAX_BL_LEVEL;
props.type = BACKLIGHT_RAW;
snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
- adev_to_drm(dm->adev)->primary->index);
+ adev_to_drm(dm->adev)->primary->index + dm->num_of_edps);
- dm->backlight_dev = backlight_device_register(bl_name,
- adev_to_drm(dm->adev)->dev,
- dm,
- &amdgpu_dm_backlight_ops,
- &props);
+ dm->backlight_dev[dm->num_of_edps] = backlight_device_register(bl_name,
+ adev_to_drm(dm->adev)->dev,
+ dm,
+ &amdgpu_dm_backlight_ops,
+ &props);
- if (IS_ERR(dm->backlight_dev))
+ if (IS_ERR(dm->backlight_dev[dm->num_of_edps]))
DRM_ERROR("DM: Backlight registration failed!\n");
else
DRM_DEBUG_DRIVER("DM: Registered Backlight device: %s\n", bl_name);
}
-
#endif
static int initialize_plane(struct amdgpu_display_manager *dm,
@@ -3675,10 +3685,10 @@ static void register_backlight_device(struct amdgpu_display_manager *dm,
* DM initialization because not having a backlight control
* is better then a black screen.
*/
- if (!dm->backlight_dev)
+ if (!dm->backlight_dev[dm->num_of_edps])
amdgpu_dm_register_backlight_device(dm);
- if (dm->backlight_dev) {
+ if (dm->backlight_dev[dm->num_of_edps]) {
dm->backlight_link[dm->num_of_edps] = link;
dm->num_of_edps++;
}
@@ -4747,7 +4757,7 @@ fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
const bool force_disable_dcc)
{
const uint64_t modifier = afb->base.modifier;
- int ret;
+ int ret = 0;
fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
@@ -4765,9 +4775,9 @@ fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
if (ret)
- return ret;
+ drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
- return 0;
+ return ret;
}
static int
@@ -6198,6 +6208,7 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
const struct dc_link *link = aconnector->dc_link;
struct amdgpu_device *adev = drm_to_adev(connector->dev);
struct amdgpu_display_manager *dm = &adev->dm;
+ int i;
/*
* Call only if mst_mgr was iniitalized before since it's not done
@@ -6208,12 +6219,11 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
-
- if ((link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) &&
- link->type != dc_connection_none &&
- dm->backlight_dev) {
- backlight_device_unregister(dm->backlight_dev);
- dm->backlight_dev = NULL;
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if ((link == dm->backlight_link[i]) && dm->backlight_dev[i]) {
+ backlight_device_unregister(dm->backlight_dev[i]);
+ dm->backlight_dev[i] = NULL;
+ }
}
#endif
@@ -7570,8 +7580,10 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
* 60 - Commonly used
* 48,72,96 - Multiples of 24
*/
- const uint32_t common_rates[] = { 23976, 24000, 25000, 29970, 30000,
- 48000, 50000, 60000, 72000, 96000 };
+ static const uint32_t common_rates[] = {
+ 23976, 24000, 25000, 29970, 30000,
+ 48000, 50000, 60000, 72000, 96000
+ };
/*
* Find mode with highest refresh rate with the same resolution
@@ -9191,8 +9203,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
/* restore the backlight level */
- if (dm->backlight_dev && (amdgpu_dm_backlight_get_level(dm) != dm->brightness[0]))
- amdgpu_dm_backlight_set_level(dm, dm->brightness[0]);
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if (dm->backlight_dev[i] &&
+ (amdgpu_dm_backlight_get_level(dm, i) != dm->brightness[i]))
+ amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
+ }
#endif
/*
* send vblank event on all events not handled in flip and
@@ -10549,13 +10564,68 @@ static bool is_dp_capable_without_timing_msa(struct dc *dc,
return capable;
}
-static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
+static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
+ unsigned int offset,
+ unsigned int total_length,
+ uint8_t *data,
+ unsigned int length,
+ struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+ bool res;
+ union dmub_rb_cmd cmd;
+ struct dmub_cmd_send_edid_cea *input;
+ struct dmub_cmd_edid_cea_output *output;
+
+ if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES)
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ input = &cmd.edid_cea.data.input;
+
+ cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA;
+ cmd.edid_cea.header.sub_type = 0;
+ cmd.edid_cea.header.payload_bytes =
+ sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
+ input->offset = offset;
+ input->length = length;
+ input->total_length = total_length;
+ memcpy(input->payload, data, length);
+
+ res = dc_dmub_srv_cmd_with_reply_data(dm->dc->ctx->dmub_srv, &cmd);
+ if (!res) {
+ DRM_ERROR("EDID CEA parser failed\n");
+ return false;
+ }
+
+ output = &cmd.edid_cea.data.output;
+
+ if (output->type == DMUB_CMD__EDID_CEA_ACK) {
+ if (!output->ack.success) {
+ DRM_ERROR("EDID CEA ack failed at offset %d\n",
+ output->ack.offset);
+ }
+ } else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) {
+ if (!output->amd_vsdb.vsdb_found)
+ return false;
+
+ vsdb->freesync_supported = output->amd_vsdb.freesync_supported;
+ vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version;
+ vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate;
+ vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate;
+ } else {
+ DRM_WARN("Unknown EDID CEA parser results\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
uint8_t *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
int i;
- struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
- struct dc *dc = adev->dm.dc;
/* send extension block to DMCU for parsing */
for (i = 0; i < len; i += 8) {
@@ -10563,14 +10633,14 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
int offset;
/* send 8 bytes a time */
- if (!dc_edid_parser_send_cea(dc, i, len, &edid_ext[i], 8))
+ if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8))
return false;
if (i+8 == len) {
/* EDID block sent completed, expect result */
int version, min_rate, max_rate;
- res = dc_edid_parser_recv_amd_vsdb(dc, &version, &min_rate, &max_rate);
+ res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate);
if (res) {
/* amd vsdb found */
vsdb_info->freesync_supported = 1;
@@ -10584,7 +10654,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
}
/* check for ack*/
- res = dc_edid_parser_recv_cea_ack(dc, &offset);
+ res = dc_edid_parser_recv_cea_ack(dm->dc, &offset);
if (!res)
return false;
}
@@ -10592,6 +10662,34 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
return false;
}
+static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
+ uint8_t *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+{
+ int i;
+
+ /* send extension block to DMCU for parsing */
+ for (i = 0; i < len; i += 8) {
+ /* send 8 bytes a time */
+ if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info))
+ return false;
+ }
+
+ return vsdb_info->freesync_supported;
+}
+
+static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
+ uint8_t *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+{
+ struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+
+ if (adev->dm.dmub_srv)
+ return parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
+ else
+ return parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
+}
+
static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
{