aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/amdgpu_dm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c979
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h22
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c3
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c668
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h37
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c55
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c102
9 files changed, 1300 insertions, 572 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 a717a4904268..e2b23486ba4c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
static int amdgpu_dm_init(struct amdgpu_device *adev);
static void amdgpu_dm_fini(struct amdgpu_device *adev);
+static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
+{
+ switch (link->dpcd_caps.dongle_type) {
+ case DISPLAY_DONGLE_NONE:
+ return DRM_MODE_SUBCONNECTOR_Native;
+ case DISPLAY_DONGLE_DP_VGA_CONVERTER:
+ return DRM_MODE_SUBCONNECTOR_VGA;
+ case DISPLAY_DONGLE_DP_DVI_CONVERTER:
+ case DISPLAY_DONGLE_DP_DVI_DONGLE:
+ return DRM_MODE_SUBCONNECTOR_DVID;
+ case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
+ case DISPLAY_DONGLE_DP_HDMI_DONGLE:
+ return DRM_MODE_SUBCONNECTOR_HDMIA;
+ case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
+ default:
+ return DRM_MODE_SUBCONNECTOR_Unknown;
+ }
+}
+
+static void update_subconnector_property(struct amdgpu_dm_connector *aconnector)
+{
+ struct dc_link *link = aconnector->dc_link;
+ struct drm_connector *connector = &aconnector->base;
+ enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+ if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+ return;
+
+ if (aconnector->dc_sink)
+ subconnector = get_subconnector_type(link);
+
+ drm_object_property_set_value(&connector->base,
+ connector->dev->mode_config.dp_subconnector_property,
+ subconnector);
+}
+
/*
* initializes drm_device display related structures, based on the information
* provided by DAL. The drm strcutures are: drm_crtc, drm_connector,
@@ -171,7 +207,7 @@ static void amdgpu_dm_set_psr_caps(struct dc_link *link);
static bool amdgpu_dm_psr_enable(struct dc_stream_state *stream);
static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream);
static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream);
-
+static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm);
/*
* dm_vblank_get_counter
@@ -192,17 +228,14 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
return 0;
else {
struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
- acrtc->base.state);
-
- if (acrtc_state->stream == NULL) {
+ if (acrtc->dm_irq_params.stream == NULL) {
DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
crtc);
return 0;
}
- return dc_stream_get_vblank_counter(acrtc_state->stream);
+ return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);
}
}
@@ -215,10 +248,8 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
return -EINVAL;
else {
struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
- acrtc->base.state);
- if (acrtc_state->stream == NULL) {
+ if (acrtc->dm_irq_params.stream == NULL) {
DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
crtc);
return 0;
@@ -228,7 +259,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
* TODO rework base driver to use values directly.
* for now parse it back into reg-format
*/
- dc_stream_get_scanoutpos(acrtc_state->stream,
+ dc_stream_get_scanoutpos(acrtc->dm_irq_params.stream,
&v_blank_start,
&v_blank_end,
&h_position,
@@ -268,7 +299,7 @@ static struct amdgpu_crtc *
get_crtc_by_otg_inst(struct amdgpu_device *adev,
int otg_inst)
{
- struct drm_device *dev = adev->ddev;
+ struct drm_device *dev = adev_to_drm(adev);
struct drm_crtc *crtc;
struct amdgpu_crtc *amdgpu_crtc;
@@ -287,6 +318,14 @@ get_crtc_by_otg_inst(struct amdgpu_device *adev,
return NULL;
}
+static inline bool amdgpu_dm_vrr_active_irq(struct amdgpu_crtc *acrtc)
+{
+ return acrtc->dm_irq_params.freesync_config.state ==
+ VRR_STATE_ACTIVE_VARIABLE ||
+ acrtc->dm_irq_params.freesync_config.state ==
+ VRR_STATE_ACTIVE_FIXED;
+}
+
static inline bool amdgpu_dm_vrr_active(struct dm_crtc_state *dm_state)
{
return dm_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE ||
@@ -307,7 +346,6 @@ static void dm_pflip_high_irq(void *interrupt_params)
struct amdgpu_device *adev = irq_params->adev;
unsigned long flags;
struct drm_pending_vblank_event *e;
- struct dm_crtc_state *acrtc_state;
uint32_t vpos, hpos, v_blank_start, v_blank_end;
bool vrr_active;
@@ -320,7 +358,7 @@ static void dm_pflip_high_irq(void *interrupt_params)
return;
}
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
@@ -328,7 +366,7 @@ static void dm_pflip_high_irq(void *interrupt_params)
AMDGPU_FLIP_SUBMITTED,
amdgpu_crtc->crtc_id,
amdgpu_crtc);
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
return;
}
@@ -339,12 +377,11 @@ static void dm_pflip_high_irq(void *interrupt_params)
if (!e)
WARN_ON(1);
- acrtc_state = to_dm_crtc_state(amdgpu_crtc->base.state);
- vrr_active = amdgpu_dm_vrr_active(acrtc_state);
+ vrr_active = amdgpu_dm_vrr_active_irq(amdgpu_crtc);
/* Fixed refresh rate, or VRR scanout position outside front-porch? */
if (!vrr_active ||
- !dc_stream_get_scanoutpos(acrtc_state->stream, &v_blank_start,
+ !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start,
&v_blank_end, &hpos, &vpos) ||
(vpos < v_blank_start)) {
/* Update to correct count and vblank timestamp if racing with
@@ -380,7 +417,7 @@ static void dm_pflip_high_irq(void *interrupt_params)
e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base);
e->pipe = amdgpu_crtc->crtc_id;
- list_add_tail(&e->base.link, &adev->ddev->vblank_event_list);
+ list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list);
e = NULL;
}
@@ -389,11 +426,11 @@ static void dm_pflip_high_irq(void *interrupt_params)
* of pageflip completion, so last_flip_vblank is the forbidden count
* for queueing new pageflips if vsync + VRR is enabled.
*/
- amdgpu_crtc->last_flip_vblank =
+ amdgpu_crtc->dm_irq_params.last_flip_vblank =
amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base);
amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
amdgpu_crtc->crtc_id, amdgpu_crtc,
@@ -405,17 +442,17 @@ static void dm_vupdate_high_irq(void *interrupt_params)
struct common_irq_params *irq_params = interrupt_params;
struct amdgpu_device *adev = irq_params->adev;
struct amdgpu_crtc *acrtc;
- struct dm_crtc_state *acrtc_state;
unsigned long flags;
+ int vrr_active;
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);
if (acrtc) {
- acrtc_state = to_dm_crtc_state(acrtc->base.state);
+ vrr_active = amdgpu_dm_vrr_active_irq(acrtc);
DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n",
acrtc->crtc_id,
- amdgpu_dm_vrr_active(acrtc_state));
+ vrr_active);
/* Core vblank handling is done here after end of front-porch in
* vrr mode, as vblank timestamping will give valid results
@@ -423,23 +460,23 @@ static void dm_vupdate_high_irq(void *interrupt_params)
* page-flip completion events that have been queued to us
* if a pageflip happened inside front-porch.
*/
- if (amdgpu_dm_vrr_active(acrtc_state)) {
+ if (vrr_active) {
drm_crtc_handle_vblank(&acrtc->base);
/* BTR processing for pre-DCE12 ASICs */
- if (acrtc_state->stream &&
+ if (acrtc->dm_irq_params.stream &&
adev->family < AMDGPU_FAMILY_AI) {
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
mod_freesync_handle_v_update(
adev->dm.freesync_module,
- acrtc_state->stream,
- &acrtc_state->vrr_params);
+ acrtc->dm_irq_params.stream,
+ &acrtc->dm_irq_params.vrr_params);
dc_stream_adjust_vmin_vmax(
adev->dm.dc,
- acrtc_state->stream,
- &acrtc_state->vrr_params.adjust);
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ acrtc->dm_irq_params.stream,
+ &acrtc->dm_irq_params.vrr_params.adjust);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
}
}
@@ -457,18 +494,17 @@ static void dm_crtc_high_irq(void *interrupt_params)
struct common_irq_params *irq_params = interrupt_params;
struct amdgpu_device *adev = irq_params->adev;
struct amdgpu_crtc *acrtc;
- struct dm_crtc_state *acrtc_state;
unsigned long flags;
+ int vrr_active;
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
if (!acrtc)
return;
- acrtc_state = to_dm_crtc_state(acrtc->base.state);
+ vrr_active = amdgpu_dm_vrr_active_irq(acrtc);
DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
- amdgpu_dm_vrr_active(acrtc_state),
- acrtc_state->active_planes);
+ vrr_active, acrtc->dm_irq_params.active_planes);
/**
* Core vblank handling at start of front-porch is only possible
@@ -476,7 +512,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
* valid results while done in front-porch. Otherwise defer it
* to dm_vupdate_high_irq after end of front-porch.
*/
- if (!amdgpu_dm_vrr_active(acrtc_state))
+ if (!vrr_active)
drm_crtc_handle_vblank(&acrtc->base);
/**
@@ -489,16 +525,18 @@ static void dm_crtc_high_irq(void *interrupt_params)
if (adev->family < AMDGPU_FAMILY_AI)
return;
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- if (acrtc_state->stream && acrtc_state->vrr_params.supported &&
- acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {
+ if (acrtc->dm_irq_params.stream &&
+ acrtc->dm_irq_params.vrr_params.supported &&
+ acrtc->dm_irq_params.freesync_config.state ==
+ VRR_STATE_ACTIVE_VARIABLE) {
mod_freesync_handle_v_update(adev->dm.freesync_module,
- acrtc_state->stream,
- &acrtc_state->vrr_params);
+ acrtc->dm_irq_params.stream,
+ &acrtc->dm_irq_params.vrr_params);
- dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc_state->stream,
- &acrtc_state->vrr_params.adjust);
+ dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream,
+ &acrtc->dm_irq_params.vrr_params.adjust);
}
/*
@@ -513,7 +551,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
*/
if (adev->family >= AMDGPU_FAMILY_RV &&
acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
- acrtc_state->active_planes == 0) {
+ acrtc->dm_irq_params.active_planes == 0) {
if (acrtc->event) {
drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
acrtc->event = NULL;
@@ -522,7 +560,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
acrtc->pflip_status = AMDGPU_FLIP_NONE;
}
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
static int dm_set_clockgating_state(void *handle,
@@ -544,7 +582,7 @@ static int dm_early_init(void* handle);
static void amdgpu_dm_fbc_init(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct dm_comressor_info *compressor = &adev->dm.compressor;
struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
struct drm_display_mode *mode;
@@ -586,7 +624,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
unsigned char *buf, int max_bytes)
{
struct drm_device *dev = dev_get_drvdata(kdev);
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct amdgpu_dm_connector *aconnector;
@@ -625,7 +663,7 @@ static int amdgpu_dm_audio_component_bind(struct device *kdev,
struct device *hda_kdev, void *data)
{
struct drm_device *dev = dev_get_drvdata(kdev);
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct drm_audio_component *acomp = data;
acomp->ops = &amdgpu_dm_audio_component_ops;
@@ -639,7 +677,7 @@ static void amdgpu_dm_audio_component_unbind(struct device *kdev,
struct device *hda_kdev, void *data)
{
struct drm_device *dev = dev_get_drvdata(kdev);
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct drm_audio_component *acomp = data;
acomp->ops = NULL;
@@ -842,6 +880,45 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
return 0;
}
+static void amdgpu_check_debugfs_connector_property_change(struct amdgpu_device *adev,
+ struct drm_atomic_state *state)
+{
+ struct drm_connector *connector;
+ struct drm_crtc *crtc;
+ struct amdgpu_dm_connector *amdgpu_dm_connector;
+ struct drm_connector_state *conn_state;
+ struct dm_crtc_state *acrtc_state;
+ struct drm_crtc_state *crtc_state;
+ struct dc_stream_state *stream;
+ struct drm_device *dev = adev_to_drm(adev);
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+
+ amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
+ conn_state = connector->state;
+
+ if (!(conn_state && conn_state->crtc))
+ continue;
+
+ crtc = conn_state->crtc;
+ acrtc_state = to_dm_crtc_state(crtc->state);
+
+ if (!(acrtc_state && acrtc_state->stream))
+ continue;
+
+ stream = acrtc_state->stream;
+
+ if (amdgpu_dm_connector->dsc_settings.dsc_force_enable ||
+ amdgpu_dm_connector->dsc_settings.dsc_num_slices_v ||
+ amdgpu_dm_connector->dsc_settings.dsc_num_slices_h ||
+ amdgpu_dm_connector->dsc_settings.dsc_bits_per_pixel) {
+ conn_state = drm_atomic_get_connector_state(state, connector);
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ crtc_state->mode_changed = true;
+ }
+ }
+}
+
static int amdgpu_dm_init(struct amdgpu_device *adev)
{
struct dc_init_data init_data;
@@ -850,7 +927,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
#endif
int r;
- adev->dm.ddev = adev->ddev;
+ adev->dm.ddev = adev_to_drm(adev);
adev->dm.adev = adev;
/* Zero all the fields */
@@ -986,10 +1063,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
/* TODO: Add_display_info? */
/* TODO use dynamic cursor width */
- adev->ddev->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size;
- adev->ddev->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size;
+ adev_to_drm(adev)->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size;
+ adev_to_drm(adev)->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size;
- if (drm_vblank_init(adev->ddev, adev->dm.display_indexes_num)) {
+ if (drm_vblank_init(adev_to_drm(adev), adev->dm.display_indexes_num)) {
DRM_ERROR(
"amdgpu: failed to initialize sw for display support.\n");
goto error;
@@ -1066,6 +1143,12 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
const struct dmcu_firmware_header_v1_0 *hdr;
switch(adev->asic_type) {
+#if defined(CONFIG_DRM_AMD_DC_SI)
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ case CHIP_OLAND:
+#endif
case CHIP_BONAIRE:
case CHIP_HAWAII:
case CHIP_KAVERI:
@@ -1383,9 +1466,6 @@ static int dm_late_init(void *handle)
struct dmcu *dmcu = NULL;
bool ret = true;
- if (!adev->dm.fw_dmcu && !adev->dm.dmub_fw)
- return detect_mst_link_for_all_connectors(adev->ddev);
-
dmcu = adev->dm.dc->res_pool->dmcu;
for (i = 0; i < 16; i++)
@@ -1414,7 +1494,7 @@ static int dm_late_init(void *handle)
if (!ret)
return -EINVAL;
- return detect_mst_link_for_all_connectors(adev->ddev);
+ return detect_mst_link_for_all_connectors(adev_to_drm(adev));
}
static void s3_handle_mst(struct drm_device *dev, bool suspend)
@@ -1652,7 +1732,7 @@ static int dm_suspend(void *handle)
struct amdgpu_display_manager *dm = &adev->dm;
int ret = 0;
- if (adev->in_gpu_reset) {
+ if (amdgpu_in_reset(adev)) {
mutex_lock(&dm->dc_lock);
dm->cached_dc_state = dc_copy_state(dm->dc->current_state);
@@ -1666,9 +1746,9 @@ static int dm_suspend(void *handle)
}
WARN_ON(adev->dm.cached_state);
- adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
+ adev->dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev));
- s3_handle_mst(adev->ddev, true);
+ s3_handle_mst(adev_to_drm(adev), true);
amdgpu_dm_irq_suspend(adev);
@@ -1822,7 +1902,7 @@ cleanup:
static int dm_resume(void *handle)
{
struct amdgpu_device *adev = handle;
- struct drm_device *ddev = adev->ddev;
+ struct drm_device *ddev = adev_to_drm(adev);
struct amdgpu_display_manager *dm = &adev->dm;
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
@@ -1838,7 +1918,7 @@ static int dm_resume(void *handle)
struct dc_state *dc_state;
int i, r, j;
- if (adev->in_gpu_reset) {
+ if (amdgpu_in_reset(adev)) {
dc_state = dm->cached_dc_state;
r = dm_dmub_hw_init(adev);
@@ -2044,7 +2124,7 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
return;
conn_base = &aconnector->base;
- adev = conn_base->dev->dev_private;
+ adev = drm_to_adev(conn_base->dev);
dm = &adev->dm;
caps = &dm->backlight_caps;
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
@@ -2095,7 +2175,6 @@ void amdgpu_dm_update_connector_after_detect(
if (aconnector->mst_mgr.mst_state == true)
return;
-
sink = aconnector->dc_link->local_sink;
if (sink)
dc_sink_retain(sink);
@@ -2222,6 +2301,8 @@ void amdgpu_dm_update_connector_after_detect(
mutex_unlock(&dev->mode_config.mutex);
+ update_subconnector_property(aconnector);
+
if (sink)
dc_sink_release(sink);
}
@@ -2233,7 +2314,7 @@ static void handle_hpd_irq(void *param)
struct drm_device *dev = connector->dev;
enum dc_connection_type new_connection_type = dc_connection_none;
#ifdef CONFIG_DRM_AMD_DC_HDCP
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
#endif
/*
@@ -2366,7 +2447,7 @@ static void handle_hpd_rx_irq(void *param)
enum dc_connection_type new_connection_type = dc_connection_none;
#ifdef CONFIG_DRM_AMD_DC_HDCP
union hpd_irq_data hpd_irq_data;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
#endif
@@ -2437,7 +2518,7 @@ static void handle_hpd_rx_irq(void *param)
static void register_hpd_handlers(struct amdgpu_device *adev)
{
- struct drm_device *dev = adev->ddev;
+ struct drm_device *dev = adev_to_drm(adev);
struct drm_connector *connector;
struct amdgpu_dm_connector *aconnector;
const struct dc_link *dc_link;
@@ -2474,6 +2555,89 @@ static void register_hpd_handlers(struct amdgpu_device *adev)
}
}
+#if defined(CONFIG_DRM_AMD_DC_SI)
+/* Register IRQ sources and initialize IRQ callbacks */
+static int dce60_register_irq_handlers(struct amdgpu_device *adev)
+{
+ struct dc *dc = adev->dm.dc;
+ struct common_irq_params *c_irq_params;
+ struct dc_interrupt_params int_params = {0};
+ int r;
+ int i;
+ unsigned client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
+
+ int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+ int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+
+ /*
+ * Actions of amdgpu_irq_add_id():
+ * 1. Register a set() function with base driver.
+ * Base driver will call set() function to enable/disable an
+ * interrupt in DC hardware.
+ * 2. Register amdgpu_dm_irq_handler().
+ * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+ * coming from DC hardware.
+ * amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+ * for acknowledging and handling. */
+
+ /* Use VBLANK interrupt */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ r = amdgpu_irq_add_id(adev, client_id, i+1 , &adev->crtc_irq);
+ if (r) {
+ DRM_ERROR("Failed to add crtc irq id!\n");
+ return r;
+ }
+
+ int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+ int_params.irq_source =
+ dc_interrupt_to_irq_source(dc, i+1 , 0);
+
+ c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
+
+ c_irq_params->adev = adev;
+ c_irq_params->irq_src = int_params.irq_source;
+
+ amdgpu_dm_irq_register_interrupt(adev, &int_params,
+ dm_crtc_high_irq, c_irq_params);
+ }
+
+ /* Use GRPH_PFLIP interrupt */
+ for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP;
+ i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) {
+ r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq);
+ if (r) {
+ DRM_ERROR("Failed to add page flip irq id!\n");
+ return r;
+ }
+
+ int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+ int_params.irq_source =
+ dc_interrupt_to_irq_source(dc, i, 0);
+
+ c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
+
+ c_irq_params->adev = adev;
+ c_irq_params->irq_src = int_params.irq_source;
+
+ amdgpu_dm_irq_register_interrupt(adev, &int_params,
+ dm_pflip_high_irq, c_irq_params);
+
+ }
+
+ /* HPD */
+ r = amdgpu_irq_add_id(adev, client_id,
+ VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq);
+ if (r) {
+ DRM_ERROR("Failed to add hpd irq id!\n");
+ return r;
+ }
+
+ register_hpd_handlers(adev);
+
+ return 0;
+}
+#endif
+
/* Register IRQ sources and initialize IRQ callbacks */
static int dce110_register_irq_handlers(struct amdgpu_device *adev)
{
@@ -2704,7 +2868,7 @@ static int dm_atomic_get_state(struct drm_atomic_state *state,
struct dm_atomic_state **dm_state)
{
struct drm_device *dev = state->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_display_manager *dm = &adev->dm;
struct drm_private_state *priv_state;
@@ -2724,7 +2888,7 @@ static struct dm_atomic_state *
dm_atomic_get_new_state(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_display_manager *dm = &adev->dm;
struct drm_private_obj *obj;
struct drm_private_state *new_obj_state;
@@ -2738,24 +2902,6 @@ dm_atomic_get_new_state(struct drm_atomic_state *state)
return NULL;
}
-static struct dm_atomic_state *
-dm_atomic_get_old_state(struct drm_atomic_state *state)
-{
- struct drm_device *dev = state->dev;
- struct amdgpu_device *adev = dev->dev_private;
- struct amdgpu_display_manager *dm = &adev->dm;
- struct drm_private_obj *obj;
- struct drm_private_state *old_obj_state;
- int i;
-
- for_each_old_private_obj_in_state(state, obj, old_obj_state, i) {
- if (obj->funcs == dm->atomic_obj.funcs)
- return to_dm_atomic_state(old_obj_state);
- }
-
- return NULL;
-}
-
static struct drm_private_state *
dm_atomic_duplicate_state(struct drm_private_obj *obj)
{
@@ -2803,18 +2949,18 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
adev->mode_info.mode_config_initialized = true;
- adev->ddev->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs;
- adev->ddev->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs;
+ adev_to_drm(adev)->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs;
+ adev_to_drm(adev)->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs;
- adev->ddev->mode_config.max_width = 16384;
- adev->ddev->mode_config.max_height = 16384;
+ adev_to_drm(adev)->mode_config.max_width = 16384;
+ adev_to_drm(adev)->mode_config.max_height = 16384;
- adev->ddev->mode_config.preferred_depth = 24;
- adev->ddev->mode_config.prefer_shadow = 1;
+ adev_to_drm(adev)->mode_config.preferred_depth = 24;
+ adev_to_drm(adev)->mode_config.prefer_shadow = 1;
/* indicates support for immediate flip */
- adev->ddev->mode_config.async_page_flip = true;
+ adev_to_drm(adev)->mode_config.async_page_flip = true;
- adev->ddev->mode_config.fb_base = adev->gmc.aper_base;
+ adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
@@ -2828,7 +2974,7 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
dc_resource_state_copy_construct_current(adev->dm.dc, state->context);
- drm_atomic_private_obj_init(adev->ddev,
+ drm_atomic_private_obj_init(adev_to_drm(adev),
&adev->dm.atomic_obj,
&state->base,
&dm_atomic_state_funcs);
@@ -3000,13 +3146,13 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
props.type = BACKLIGHT_RAW;
snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
- dm->adev->ddev->primary->index);
+ adev_to_drm(dm->adev)->primary->index);
dm->backlight_dev = backlight_device_register(bl_name,
- dm->adev->ddev->dev,
- dm,
- &amdgpu_dm_backlight_ops,
- &props);
+ adev_to_drm(dm->adev)->dev,
+ dm,
+ &amdgpu_dm_backlight_ops,
+ &props);
if (IS_ERR(dm->backlight_dev))
DRM_ERROR("DM: Backlight registration failed!\n");
@@ -3212,6 +3358,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
/* Software is initialized. Now we can register interrupt handlers. */
switch (adev->asic_type) {
+#if defined(CONFIG_DRM_AMD_DC_SI)
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ case CHIP_OLAND:
+ if (dce60_register_irq_handlers(dm->adev)) {
+ DRM_ERROR("DM: Failed to initialize IRQ\n");
+ goto fail;
+ }
+ break;
+#endif
case CHIP_BONAIRE:
case CHIP_HAWAII:
case CHIP_KAVERI:
@@ -3254,9 +3411,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
goto fail;
}
- /* No userspace support. */
- dm->dc->debug.disable_tri_buf = true;
-
return 0;
fail:
kfree(aencoder);
@@ -3312,14 +3466,14 @@ static ssize_t s3_debug_store(struct device *device,
int ret;
int s3_state;
struct drm_device *drm_dev = dev_get_drvdata(device);
- struct amdgpu_device *adev = drm_dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(drm_dev);
ret = kstrtoint(buf, 0, &s3_state);
if (ret == 0) {
if (s3_state) {
dm_resume(adev);
- drm_kms_helper_hotplug_event(adev->ddev);
+ drm_kms_helper_hotplug_event(adev_to_drm(adev));
} else
dm_suspend(adev);
}
@@ -3336,6 +3490,20 @@ static int dm_early_init(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
switch (adev->asic_type) {
+#if defined(CONFIG_DRM_AMD_DC_SI)
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ adev->mode_info.num_crtc = 6;
+ adev->mode_info.num_hpd = 6;
+ adev->mode_info.num_dig = 6;
+ break;
+ case CHIP_OLAND:
+ adev->mode_info.num_crtc = 2;
+ adev->mode_info.num_hpd = 2;
+ adev->mode_info.num_dig = 2;
+ break;
+#endif
case CHIP_BONAIRE:
case CHIP_HAWAII:
adev->mode_info.num_crtc = 6;
@@ -3432,7 +3600,7 @@ static int dm_early_init(void *handle)
*/
#if defined(CONFIG_DEBUG_KERNEL_DC)
device_create_file(
- adev->ddev->dev,
+ adev_to_drm(adev)->dev,
&dev_attr_s3_debug);
#endif
@@ -3443,21 +3611,12 @@ static bool modeset_required(struct drm_crtc_state *crtc_state,
struct dc_stream_state *new_stream,
struct dc_stream_state *old_stream)
{
- if (!drm_atomic_crtc_needs_modeset(crtc_state))
- return false;
-
- if (!crtc_state->enable)
- return false;
-
- return crtc_state->active;
+ return crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
}
static bool modereset_required(struct drm_crtc_state *crtc_state)
{
- if (!drm_atomic_crtc_needs_modeset(crtc_state))
- return false;
-
- return !crtc_state->enable || !crtc_state->active;
+ return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
}
static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
@@ -3530,8 +3689,17 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state,
static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
uint64_t *tiling_flags, bool *tmz_surface)
{
- struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]);
- int r = amdgpu_bo_reserve(rbo, false);
+ struct amdgpu_bo *rbo;
+ int r;
+
+ if (!amdgpu_fb) {
+ *tiling_flags = 0;
+ *tmz_surface = false;
+ return 0;
+ }
+
+ rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]);
+ r = amdgpu_bo_reserve(rbo, false);
if (unlikely(r)) {
/* Don't show error message when returning -ERESTARTSYS */
@@ -3954,13 +4122,10 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
struct drm_crtc_state *crtc_state)
{
struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
- const struct amdgpu_framebuffer *amdgpu_fb =
- to_amdgpu_framebuffer(plane_state->fb);
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
struct dc_scaling_info scaling_info;
struct dc_plane_info plane_info;
- uint64_t tiling_flags;
int ret;
- bool tmz_surface = false;
bool force_disable_dcc = false;
ret = fill_dc_scaling_info(plane_state, &scaling_info);
@@ -3972,15 +4137,12 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
dc_plane_state->clip_rect = scaling_info.clip_rect;
dc_plane_state->scaling_quality = scaling_info.scaling_quality;
- ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface);
- if (ret)
- return ret;
-
force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
- ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags,
+ ret = fill_dc_plane_info_and_addr(adev, plane_state,
+ dm_plane_state->tiling_flags,
&plane_info,
&dc_plane_state->address,
- tmz_surface,
+ dm_plane_state->tmz_surface,
force_disable_dcc);
if (ret)
return ret;
@@ -4562,7 +4724,11 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
dc_link_get_link_cap(aconnector->dc_link));
#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dsc_caps.is_dsc_supported)
+ if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) {
+ /* Set DSC policy according to dsc_clock_en */
+ dc_dsc_policy_set_enable_dsc_when_not_needed(
+ aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
+
if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
&dsc_caps,
aconnector->dc_link->ctx->dc->debug.dsc_min_slice_height_override,
@@ -4570,6 +4736,19 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
&stream->timing,
&stream->timing.dsc_cfg))
stream->timing.flags.DSC = 1;
+ /* Overwrite the stream flag if DSC is enabled through debugfs */
+ if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE)
+ stream->timing.flags.DSC = 1;
+
+ if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h)
+ stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h;
+
+ if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v)
+ stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
+
+ if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel)
+ stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel;
+ }
#endif
}
@@ -4583,7 +4762,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
update_stream_signal(stream, sink);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
- mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
+ mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
+
if (stream->link->psr_settings.psr_feature_enabled) {
//
// should decide stream support vsc sdp colorimetry capability
@@ -4663,7 +4843,6 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
}
state->active_planes = cur->active_planes;
- state->vrr_params = cur->vrr_params;
state->vrr_infopacket = cur->vrr_infopacket;
state->abm_level = cur->abm_level;
state->vrr_supported = cur->vrr_supported;
@@ -4681,7 +4860,7 @@ static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
{
enum dc_irq_source irq_source;
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
int rc;
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
@@ -4697,7 +4876,7 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
{
enum dc_irq_source irq_source;
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
int rc = 0;
@@ -4764,6 +4943,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
else
connected = (aconnector->base.force == DRM_FORCE_ON);
+ update_subconnector_property(aconnector);
+
return (connected ? connector_status_connected :
connector_status_disconnected);
}
@@ -4774,7 +4955,7 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
uint64_t val)
{
struct drm_device *dev = connector->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct dm_connector_state *dm_old_state =
to_dm_connector_state(connector->state);
struct dm_connector_state *dm_new_state =
@@ -4829,7 +5010,7 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
uint64_t *val)
{
struct drm_device *dev = connector->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct dm_connector_state *dm_state =
to_dm_connector_state(state);
int ret = -EINVAL;
@@ -4879,9 +5060,16 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
const struct dc_link *link = aconnector->dc_link;
- struct amdgpu_device *adev = connector->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(connector->dev);
struct amdgpu_display_manager *dm = &adev->dm;
+ /*
+ * Call only if mst_mgr was iniitalized before since it's not done
+ * for all connector types.
+ */
+ if (aconnector->mst_mgr.dev)
+ drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
+
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
@@ -5064,7 +5252,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct dc_stream_state *old_stream)
{
struct drm_connector *connector = &aconnector->base;
- struct amdgpu_device *adev = connector->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(connector->dev);
struct dc_stream_state *stream;
const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL;
int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
@@ -5328,7 +5516,7 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
- struct amdgpu_device *adev = crtc->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dc *dc = adev->dm.dc;
struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state);
int ret = -EINVAL;
@@ -5549,6 +5737,10 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
dc_plane_state_retain(dm_plane_state->dc_state);
}
+ /* Framebuffer hasn't been updated yet, so retain old flags. */
+ dm_plane_state->tiling_flags = old_dm_plane_state->tiling_flags;
+ dm_plane_state->tmz_surface = old_dm_plane_state->tmz_surface;
+
return &dm_plane_state->base;
}
@@ -5583,14 +5775,8 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
struct list_head list;
struct ttm_validate_buffer tv;
struct ww_acquire_ctx ticket;
- uint64_t tiling_flags;
uint32_t domain;
int r;
- bool tmz_surface = false;
- bool force_disable_dcc = false;
-
- dm_plane_state_old = to_dm_plane_state(plane->state);
- dm_plane_state_new = to_dm_plane_state(new_state);
if (!new_state->fb) {
DRM_DEBUG_DRIVER("No FB bound\n");
@@ -5634,27 +5820,35 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
return r;
}
- amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
-
- tmz_surface = amdgpu_bo_encrypted(rbo);
-
ttm_eu_backoff_reservation(&ticket, &list);
afb->address = amdgpu_bo_gpu_offset(rbo);
amdgpu_bo_ref(rbo);
+ /**
+ * We don't do surface updates on planes that have been newly created,
+ * but we also don't have the afb->address during atomic check.
+ *
+ * Fill in buffer attributes depending on the address here, but only on
+ * newly created planes since they're not being used by DC yet and this
+ * won't modify global state.
+ */
+ dm_plane_state_old = to_dm_plane_state(plane->state);
+ dm_plane_state_new = to_dm_plane_state(new_state);
+
if (dm_plane_state_new->dc_state &&
- dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
- struct dc_plane_state *plane_state = dm_plane_state_new->dc_state;
+ dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
+ struct dc_plane_state *plane_state =
+ dm_plane_state_new->dc_state;
+ bool force_disable_dcc = !plane_state->dcc.enable;
- force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
fill_plane_buffer_attributes(
adev, afb, plane_state->format, plane_state->rotation,
- tiling_flags, &plane_state->tiling_info,
- &plane_state->plane_size, &plane_state->dcc,
- &plane_state->address, tmz_surface,
- force_disable_dcc);
+ dm_plane_state_new->tiling_flags,
+ &plane_state->tiling_info, &plane_state->plane_size,
+ &plane_state->dcc, &plane_state->address,
+ dm_plane_state_new->tmz_surface, force_disable_dcc);
}
return 0;
@@ -5695,7 +5889,7 @@ static int dm_plane_helper_check_state(struct drm_plane_state *state,
static int dm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
- struct amdgpu_device *adev = plane->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
struct dc *dc = adev->dm.dc;
struct dm_plane_state *dm_plane_state;
struct dc_scaling_info scaling_info;
@@ -5864,7 +6058,7 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
num_formats = get_plane_formats(plane, plane_cap, formats,
ARRAY_SIZE(formats));
- res = drm_universal_plane_init(dm->adev->ddev, plane, possible_crtcs,
+ res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
&dm_plane_funcs, formats, num_formats,
NULL, plane->type, NULL);
if (res)
@@ -5898,8 +6092,9 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
- drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
- supported_rotations);
+ if (dm->adev->asic_type >= CHIP_BONAIRE)
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+ supported_rotations);
drm_plane_helper_add(plane, &dm_plane_helper_funcs);
@@ -6169,7 +6364,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
struct dc_link *link,
int link_index)
{
- struct amdgpu_device *adev = dm->ddev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dm->ddev);
/*
* Some of the properties below require access to state, like bpc.
@@ -6420,7 +6615,7 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev,
struct amdgpu_encoder *aencoder,
uint32_t link_index)
{
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
int res = drm_encoder_init(dev,
&aencoder->base,
@@ -6605,7 +6800,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
static void handle_cursor_update(struct drm_plane *plane,
struct drm_plane_state *old_plane_state)
{
- struct amdgpu_device *adev = plane->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
@@ -6694,6 +6889,7 @@ static void update_freesync_state_on_stream(
struct mod_vrr_params vrr_params;
struct dc_info_packet vrr_infopacket = {0};
struct amdgpu_device *adev = dm->adev;
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
unsigned long flags;
if (!new_stream)
@@ -6707,8 +6903,8 @@ static void update_freesync_state_on_stream(
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
return;
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
- vrr_params = new_crtc_state->vrr_params;
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+ vrr_params = acrtc->dm_irq_params.vrr_params;
if (surface) {
mod_freesync_handle_preflip(
@@ -6739,7 +6935,7 @@ static void update_freesync_state_on_stream(
&vrr_infopacket);
new_crtc_state->freesync_timing_changed |=
- (memcmp(&new_crtc_state->vrr_params.adjust,
+ (memcmp(&acrtc->dm_irq_params.vrr_params.adjust,
&vrr_params.adjust,
sizeof(vrr_params.adjust)) != 0);
@@ -6748,10 +6944,10 @@ static void update_freesync_state_on_stream(
&vrr_infopacket,
sizeof(vrr_infopacket)) != 0);
- new_crtc_state->vrr_params = vrr_params;
+ acrtc->dm_irq_params.vrr_params = vrr_params;
new_crtc_state->vrr_infopacket = vrr_infopacket;
- new_stream->adjust = new_crtc_state->vrr_params.adjust;
+ new_stream->adjust = acrtc->dm_irq_params.vrr_params.adjust;
new_stream->vrr_infopacket = vrr_infopacket;
if (new_crtc_state->freesync_vrr_info_changed)
@@ -6760,10 +6956,10 @@ static void update_freesync_state_on_stream(
(int)new_crtc_state->base.vrr_enabled,
(int)vrr_params.state);
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
-static void pre_update_freesync_state_on_stream(
+static void update_stream_irq_parameters(
struct amdgpu_display_manager *dm,
struct dm_crtc_state *new_crtc_state)
{
@@ -6771,6 +6967,7 @@ static void pre_update_freesync_state_on_stream(
struct mod_vrr_params vrr_params;
struct mod_freesync_config config = new_crtc_state->freesync_config;
struct amdgpu_device *adev = dm->adev;
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
unsigned long flags;
if (!new_stream)
@@ -6783,8 +6980,8 @@ static void pre_update_freesync_state_on_stream(
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
return;
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
- vrr_params = new_crtc_state->vrr_params;
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+ vrr_params = acrtc->dm_irq_params.vrr_params;
if (new_crtc_state->vrr_supported &&
config.min_refresh_in_uhz &&
@@ -6801,12 +6998,15 @@ static void pre_update_freesync_state_on_stream(
&config, &vrr_params);
new_crtc_state->freesync_timing_changed |=
- (memcmp(&new_crtc_state->vrr_params.adjust,
- &vrr_params.adjust,
- sizeof(vrr_params.adjust)) != 0);
+ (memcmp(&acrtc->dm_irq_params.vrr_params.adjust,
+ &vrr_params.adjust, sizeof(vrr_params.adjust)) != 0);
- new_crtc_state->vrr_params = vrr_params;
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ new_crtc_state->freesync_config = config;
+ /* Copy state for access from DM IRQ handler */
+ acrtc->dm_irq_params.freesync_config = config;
+ acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes;
+ acrtc->dm_irq_params.vrr_params = vrr_params;
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state,
@@ -6876,8 +7076,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
long r;
unsigned long flags;
struct amdgpu_bo *abo;
- uint64_t tiling_flags;
- bool tmz_surface = false;
uint32_t target_vblank, last_flip_vblank;
bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
bool pflip_present = false;
@@ -6961,28 +7159,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (unlikely(r <= 0))
DRM_ERROR("Waiting for fences timed out!");
- /*
- * TODO This might fail and hence better not used, wait
- * explicitly on fences instead
- * and in general should be called for
- * blocking commit to as per framework helpers
- */
- r = amdgpu_bo_reserve(abo, true);
- if (unlikely(r != 0))
- DRM_ERROR("failed to reserve buffer before flip\n");
-
- amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
-
- tmz_surface = amdgpu_bo_encrypted(abo);
-
- amdgpu_bo_unreserve(abo);
-
fill_dc_plane_info_and_addr(
- dm->adev, new_plane_state, tiling_flags,
+ dm->adev, new_plane_state,
+ dm_new_plane_state->tiling_flags,
&bundle->plane_infos[planes_count],
&bundle->flip_addrs[planes_count].address,
- tmz_surface,
- false);
+ dm_new_plane_state->tmz_surface, false);
DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n",
new_plane_state->plane->index,
@@ -7047,7 +7229,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
* on late submission of flips.
*/
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
- last_flip_vblank = acrtc_attach->last_flip_vblank;
+ last_flip_vblank = acrtc_attach->dm_irq_params.last_flip_vblank;
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
@@ -7131,7 +7313,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
dc_stream_adjust_vmin_vmax(
dm->dc, acrtc_state->stream,
- &acrtc_state->vrr_params.adjust);
+ &acrtc_attach->dm_irq_params.vrr_params.adjust);
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
mutex_lock(&dm->dc_lock);
@@ -7160,9 +7342,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
* on some ASICs).
*/
if (dm_old_crtc_state->active_planes != acrtc_state->active_planes)
- dm_update_pflip_irq_state(
- (struct amdgpu_device *)dev->dev_private,
- acrtc_attach);
+ dm_update_pflip_irq_state(drm_to_adev(dev),
+ acrtc_attach);
if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
@@ -7192,7 +7373,7 @@ cleanup:
static void amdgpu_dm_commit_audio(struct drm_device *dev,
struct drm_atomic_state *state)
{
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
struct drm_connector_state *old_con_state, *new_con_state;
@@ -7282,34 +7463,6 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool nonblock)
{
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- struct amdgpu_device *adev = dev->dev_private;
- int i;
-
- /*
- * We evade vblank and pflip interrupts on CRTCs that are undergoing
- * a modeset, being disabled, or have no active planes.
- *
- * It's done in atomic commit rather than commit tail for now since
- * some of these interrupt handlers access the current CRTC state and
- * potentially the stream pointer itself.
- *
- * Since the atomic state is swapped within atomic commit and not within
- * commit tail this would leave to new state (that hasn't been committed yet)
- * being accesssed from within the handlers.
- *
- * TODO: Fix this so we can do this in commit tail and not have to block
- * in atomic check.
- */
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
-
- if (old_crtc_state->active &&
- (!new_crtc_state->active ||
- drm_atomic_crtc_needs_modeset(new_crtc_state)))
- manage_dm_interrupts(adev, acrtc, false);
- }
/*
* Add check here for SoC's that support hardware cursor plane, to
* unset legacy_cursor_update
@@ -7331,7 +7484,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_display_manager *dm = &adev->dm;
struct dm_atomic_state *dm_state;
struct dc_state *dc_state = NULL, *dc_state_temp = NULL;
@@ -7344,8 +7497,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
struct drm_connector_state *old_con_state, *new_con_state;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
int crtc_disable_count = 0;
+ bool mode_set_reset_required = false;
drm_atomic_helper_update_legacy_modeset_state(dev, state);
+ drm_atomic_helper_calc_timestamping_constants(state);
dm_state = dm_atomic_get_new_state(state);
if (dm_state && dm_state->context) {
@@ -7358,6 +7513,20 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dc_resource_state_copy_construct_current(dm->dc, dc_state);
}
+ for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+ if (old_crtc_state->active &&
+ (!new_crtc_state->active ||
+ drm_atomic_crtc_needs_modeset(new_crtc_state))) {
+ manage_dm_interrupts(adev, acrtc, false);
+ dc_stream_release(dm_old_crtc_state->stream);
+ }
+ }
+
/* update changed items */
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
@@ -7420,19 +7589,21 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
acrtc->enabled = true;
acrtc->hw_mode = new_crtc_state->mode;
crtc->hwmode = new_crtc_state->mode;
+ mode_set_reset_required = true;
} else if (modereset_required(new_crtc_state)) {
DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
/* i.e. reset mode */
- if (dm_old_crtc_state->stream) {
- if (dm_old_crtc_state->stream->link->psr_settings.psr_allow_active)
- amdgpu_dm_psr_disable(dm_old_crtc_state->stream);
-
+ if (dm_old_crtc_state->stream)
remove_stream(adev, acrtc, dm_old_crtc_state->stream);
- }
+ mode_set_reset_required = true;
}
} /* for_each_crtc_in_state() */
if (dc_state) {
+ /* if there mode set or reset, disable eDP PSR */
+ if (mode_set_reset_required)
+ amdgpu_dm_psr_disable_all(dm);
+
dm_enable_per_frame_crtc_master_sync(dc_state);
mutex_lock(&dm->dc_lock);
WARN_ON(!dc_commit_state(dm->dc, dc_state));
@@ -7451,7 +7622,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
if (!status)
status = dc_stream_get_status_from_state(dc_state,
dm_new_crtc_state->stream);
-
if (!status)
DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);
else
@@ -7577,8 +7747,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- /* Update freesync active state. */
- pre_update_freesync_state_on_stream(dm, dm_new_crtc_state);
+ /* For freesync config update on crtc state and params for irq */
+ update_stream_irq_parameters(dm, dm_new_crtc_state);
/* Handle vrr on->off / off->on transitions */
amdgpu_dm_handle_vrr_transition(dm_old_crtc_state,
@@ -7594,10 +7764,15 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
if (new_crtc_state->active &&
(!old_crtc_state->active ||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
+ dc_stream_retain(dm_new_crtc_state->stream);
+ acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
manage_dm_interrupts(adev, acrtc, true);
+
#ifdef CONFIG_DEBUG_FS
/**
* Frontend may have changed so reapply the CRC capture
@@ -7634,7 +7809,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
* send vblank event on all events not handled in flip and
* mark consumed event for drm_atomic_helper_commit_hw_done
*/
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->event)
@@ -7642,7 +7817,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
new_crtc_state->event = NULL;
}
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
/* Signal HW programming completion */
drm_atomic_helper_commit_hw_done(state);
@@ -7841,8 +8016,6 @@ static void reset_freesync_config_for_crtc(
{
new_crtc_state->vrr_supported = false;
- memset(&new_crtc_state->vrr_params, 0,
- sizeof(new_crtc_state->vrr_params));
memset(&new_crtc_state->vrr_infopacket, 0,
sizeof(new_crtc_state->vrr_infopacket));
}
@@ -7914,6 +8087,13 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
goto fail;
}
+ /*
+ * TODO: Check VSDB bits to decide whether this should
+ * be enabled or not.
+ */
+ new_stream->triggered_crtc_reset.enabled =
+ dm->force_timing_sync;
+
dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
ret = fill_hdr_info_packet(drm_new_conn_state,
@@ -8033,8 +8213,7 @@ skip_modeset:
* We want to do dc stream updates that do not require a
* full modeset below.
*/
- if (!(enable && aconnector && new_crtc_state->enable &&
- new_crtc_state->active))
+ if (!(enable && aconnector && new_crtc_state->active))
return 0;
/*
* Given above conditions, the dc state cannot be NULL because:
@@ -8125,6 +8304,8 @@ static bool should_reset_plane(struct drm_atomic_state *state,
* TODO: Come up with a more elegant solution for this.
*/
for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) {
+ struct dm_plane_state *old_dm_plane_state, *new_dm_plane_state;
+
if (other->type == DRM_PLANE_TYPE_CURSOR)
continue;
@@ -8135,9 +8316,45 @@ static bool should_reset_plane(struct drm_atomic_state *state,
if (old_other_state->crtc != new_other_state->crtc)
return true;
- /* TODO: Remove this once we can handle fast format changes. */
- if (old_other_state->fb && new_other_state->fb &&
- old_other_state->fb->format != new_other_state->fb->format)
+ /* Src/dst size and scaling updates. */
+ if (old_other_state->src_w != new_other_state->src_w ||
+ old_other_state->src_h != new_other_state->src_h ||
+ old_other_state->crtc_w != new_other_state->crtc_w ||
+ old_other_state->crtc_h != new_other_state->crtc_h)
+ return true;
+
+ /* Rotation / mirroring updates. */
+ if (old_other_state->rotation != new_other_state->rotation)
+ return true;
+
+ /* Blending updates. */
+ if (old_other_state->pixel_blend_mode !=
+ new_other_state->pixel_blend_mode)
+ return true;
+
+ /* Alpha updates. */
+ if (old_other_state->alpha != new_other_state->alpha)
+ return true;
+
+ /* Colorspace changes. */
+ if (old_other_state->color_range != new_other_state->color_range ||
+ old_other_state->color_encoding != new_other_state->color_encoding)
+ return true;
+
+ /* Framebuffer checks fall at the end. */
+ if (!old_other_state->fb || !new_other_state->fb)
+ continue;
+
+ /* Pixel format changes can require bandwidth updates. */
+ if (old_other_state->fb->format != new_other_state->fb->format)
+ return true;
+
+ old_dm_plane_state = to_dm_plane_state(old_other_state);
+ new_dm_plane_state = to_dm_plane_state(new_other_state);
+
+ /* Tiling and DCC changes also require bandwidth updates. */
+ if (old_dm_plane_state->tiling_flags !=
+ new_dm_plane_state->tiling_flags)
return true;
}
@@ -8217,8 +8434,7 @@ static int dm_update_plane_state(struct dc *dc,
dm_old_plane_state->dc_state,
dm_state->context)) {
- ret = EINVAL;
- return ret;
+ return -EINVAL;
}
@@ -8259,7 +8475,7 @@ static int dm_update_plane_state(struct dc *dc,
plane->base.id, new_plane_crtc->base.id);
ret = fill_dc_plane_attributes(
- new_plane_crtc->dev->dev_private,
+ drm_to_adev(new_plane_crtc->dev),
dc_new_plane_state,
new_plane_state,
new_crtc_state);
@@ -8305,169 +8521,6 @@ static int dm_update_plane_state(struct dc *dc,
return ret;
}
-static int
-dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm,
- struct drm_atomic_state *state,
- enum surface_update_type *out_type)
-{
- struct dc *dc = dm->dc;
- struct dm_atomic_state *dm_state = NULL, *old_dm_state = NULL;
- int i, j, num_plane, ret = 0;
- struct drm_plane_state *old_plane_state, *new_plane_state;
- struct dm_plane_state *new_dm_plane_state, *old_dm_plane_state;
- struct drm_crtc *new_plane_crtc;
- struct drm_plane *plane;
-
- struct drm_crtc *crtc;
- struct drm_crtc_state *new_crtc_state, *old_crtc_state;
- struct dm_crtc_state *new_dm_crtc_state, *old_dm_crtc_state;
- struct dc_stream_status *status = NULL;
- enum surface_update_type update_type = UPDATE_TYPE_FAST;
- struct surface_info_bundle {
- struct dc_surface_update surface_updates[MAX_SURFACES];
- struct dc_plane_info plane_infos[MAX_SURFACES];
- struct dc_scaling_info scaling_infos[MAX_SURFACES];
- struct dc_flip_addrs flip_addrs[MAX_SURFACES];
- struct dc_stream_update stream_update;
- } *bundle;
-
- bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
-
- if (!bundle) {
- DRM_ERROR("Failed to allocate update bundle\n");
- /* Set type to FULL to avoid crashing in DC*/
- update_type = UPDATE_TYPE_FULL;
- goto cleanup;
- }
-
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-
- memset(bundle, 0, sizeof(struct surface_info_bundle));
-
- new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
- old_dm_crtc_state = to_dm_crtc_state(old_crtc_state);
- num_plane = 0;
-
- if (new_dm_crtc_state->stream != old_dm_crtc_state->stream) {
- update_type = UPDATE_TYPE_FULL;
- goto cleanup;
- }
-
- if (!new_dm_crtc_state->stream)
- continue;
-
- for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) {
- const struct amdgpu_framebuffer *amdgpu_fb =
- to_amdgpu_framebuffer(new_plane_state->fb);
- struct dc_plane_info *plane_info = &bundle->plane_infos[num_plane];
- struct dc_flip_addrs *flip_addr = &bundle->flip_addrs[num_plane];
- struct dc_scaling_info *scaling_info = &bundle->scaling_infos[num_plane];
- uint64_t tiling_flags;
- bool tmz_surface = false;
-
- new_plane_crtc = new_plane_state->crtc;
- new_dm_plane_state = to_dm_plane_state(new_plane_state);
- old_dm_plane_state = to_dm_plane_state(old_plane_state);
-
- if (plane->type == DRM_PLANE_TYPE_CURSOR)
- continue;
-
- if (new_dm_plane_state->dc_state != old_dm_plane_state->dc_state) {
- update_type = UPDATE_TYPE_FULL;
- goto cleanup;
- }
-
- if (crtc != new_plane_crtc)
- continue;
-
- bundle->surface_updates[num_plane].surface =
- new_dm_plane_state->dc_state;
-
- if (new_crtc_state->mode_changed) {
- bundle->stream_update.dst = new_dm_crtc_state->stream->dst;
- bundle->stream_update.src = new_dm_crtc_state->stream->src;
- }
-
- if (new_crtc_state->color_mgmt_changed) {
- bundle->surface_updates[num_plane].gamma =
- new_dm_plane_state->dc_state->gamma_correction;
- bundle->surface_updates[num_plane].in_transfer_func =
- new_dm_plane_state->dc_state->in_transfer_func;
- bundle->surface_updates[num_plane].gamut_remap_matrix =
- &new_dm_plane_state->dc_state->gamut_remap_matrix;
- bundle->stream_update.gamut_remap =
- &new_dm_crtc_state->stream->gamut_remap_matrix;
- bundle->stream_update.output_csc_transform =
- &new_dm_crtc_state->stream->csc_color_matrix;
- bundle->stream_update.out_transfer_func =
- new_dm_crtc_state->stream->out_transfer_func;
- }
-
- ret = fill_dc_scaling_info(new_plane_state,
- scaling_info);
- if (ret)
- goto cleanup;
-
- bundle->surface_updates[num_plane].scaling_info = scaling_info;
-
- if (amdgpu_fb) {
- ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface);
- if (ret)
- goto cleanup;
-
- ret = fill_dc_plane_info_and_addr(
- dm->adev, new_plane_state, tiling_flags,
- plane_info,
- &flip_addr->address, tmz_surface,
- false);
- if (ret)
- goto cleanup;
-
- bundle->surface_updates[num_plane].plane_info = plane_info;
- bundle->surface_updates[num_plane].flip_addr = flip_addr;
- }
-
- num_plane++;
- }
-
- if (num_plane == 0)
- continue;
-
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret)
- goto cleanup;
-
- old_dm_state = dm_atomic_get_old_state(state);
- if (!old_dm_state) {
- ret = -EINVAL;
- goto cleanup;
- }
-
- status = dc_stream_get_status_from_state(old_dm_state->context,
- new_dm_crtc_state->stream);
- bundle->stream_update.stream = new_dm_crtc_state->stream;
- /*
- * TODO: DC modifies the surface during this call so we need
- * to lock here - find a way to do this without locking.
- */
- mutex_lock(&dm->dc_lock);
- update_type = dc_check_update_surfaces_for_stream(
- dc, bundle->surface_updates, num_plane,
- &bundle->stream_update, status);
- mutex_unlock(&dm->dc_lock);
-
- if (update_type > UPDATE_TYPE_MED) {
- update_type = UPDATE_TYPE_FULL;
- goto cleanup;
- }
- }
-
-cleanup:
- kfree(bundle);
-
- *out_type = update_type;
- return ret;
-}
#if defined(CONFIG_DRM_AMD_DC_DCN)
static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc)
{
@@ -8508,8 +8561,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
* acquired. For full updates case which removes/adds/updates streams on one
* CRTC while flipping on another CRTC, acquiring global lock will guarantee
* that any such full update commit will wait for completion of any outstanding
- * flip using DRMs synchronization events. See
- * dm_determine_update_type_for_commit()
+ * flip using DRMs synchronization events.
*
* Note that DM adds the affected connectors for all CRTCs in state, when that
* might not seem necessary. This is because DC stream creation requires the
@@ -8521,7 +8573,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct dm_atomic_state *dm_state = NULL;
struct dc *dc = adev->dm.dc;
struct drm_connector *connector;
@@ -8530,17 +8582,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct drm_plane *plane;
struct drm_plane_state *old_plane_state, *new_plane_state;
- enum surface_update_type update_type = UPDATE_TYPE_FAST;
- enum surface_update_type overall_update_type = UPDATE_TYPE_FAST;
enum dc_status status;
int ret, i;
-
- /*
- * This bool will be set for true for any modeset/reset
- * or plane update which implies non fast surface update.
- */
bool lock_and_validation_needed = false;
+ amdgpu_check_debugfs_connector_property_change(adev, state);
+
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
goto fail;
@@ -8633,6 +8680,17 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
}
}
+ /* Prepass for updating tiling flags on new planes. */
+ for_each_new_plane_in_state(state, plane, new_plane_state, i) {
+ struct dm_plane_state *new_dm_plane_state = to_dm_plane_state(new_plane_state);
+ struct amdgpu_framebuffer *new_afb = to_amdgpu_framebuffer(new_plane_state->fb);
+
+ ret = get_fb_info(new_afb, &new_dm_plane_state->tiling_flags,
+ &new_dm_plane_state->tmz_surface);
+ if (ret)
+ goto fail;
+ }
+
/* Remove exiting planes if they are modified */
for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
ret = dm_update_plane_state(dc, state, plane,
@@ -8721,27 +8779,23 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
continue;
- overall_update_type = UPDATE_TYPE_FULL;
lock_and_validation_needed = true;
}
- ret = dm_determine_update_type_for_commit(&adev->dm, state, &update_type);
- if (ret)
- goto fail;
-
- if (overall_update_type < update_type)
- overall_update_type = update_type;
-
- /*
- * lock_and_validation_needed was an old way to determine if we need to set
- * the global lock. Leaving it in to check if we broke any corner cases
- * lock_and_validation_needed true = UPDATE_TYPE_FULL or UPDATE_TYPE_MED
- * lock_and_validation_needed false = UPDATE_TYPE_FAST
+ /**
+ * Streams and planes are reset when there are changes that affect
+ * bandwidth. Anything that affects bandwidth needs to go through
+ * DC global validation to ensure that the configuration can be applied
+ * to hardware.
+ *
+ * We have to currently stall out here in atomic_check for outstanding
+ * commits to finish in this case because our IRQ handlers reference
+ * DRM state directly - we can end up disabling interrupts too early
+ * if we don't.
+ *
+ * TODO: Remove this stall and drop DM state private objects.
*/
- if (lock_and_validation_needed && overall_update_type <= UPDATE_TYPE_FAST)
- WARN(1, "Global lock should be Set, overall_update_type should be UPDATE_TYPE_MED or UPDATE_TYPE_FULL");
-
- if (overall_update_type > UPDATE_TYPE_FAST) {
+ if (lock_and_validation_needed) {
ret = dm_atomic_get_state(state, &dm_state);
if (ret)
goto fail;
@@ -8823,7 +8877,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct dm_crtc_state *dm_new_crtc_state =
to_dm_crtc_state(new_crtc_state);
- dm_new_crtc_state->update_type = (int)overall_update_type;
+ dm_new_crtc_state->update_type = lock_and_validation_needed ?
+ UPDATE_TYPE_FULL :
+ UPDATE_TYPE_FAST;
}
/* Must be success */
@@ -8872,7 +8928,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
struct dm_connector_state *dm_con_state = NULL;
struct drm_device *dev = connector->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
bool freesync_capable = false;
if (!connector->state) {
@@ -9071,3 +9127,34 @@ static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream)
return dc_link_set_psr_allow_active(stream->link, false, true);
}
+
+/*
+ * amdgpu_dm_psr_disable() - disable psr f/w
+ * if psr is enabled on any stream
+ *
+ * Return: true if success
+ */
+static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm)
+{
+ DRM_DEBUG_DRIVER("Disabling psr if psr is enabled on any stream\n");
+ return dc_set_psr_allow_active(dm->dc, false);
+}
+
+void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = drm_to_adev(dev);
+ struct dc *dc = adev->dm.dc;
+ int i;
+
+ mutex_lock(&adev->dm.dc_lock);
+ if (dc->current_state) {
+ for (i = 0; i < dc->current_state->stream_count; ++i)
+ dc->current_state->streams[i]
+ ->triggered_crtc_reset.enabled =
+ adev->dm.force_timing_sync;
+
+ dm_enable_per_frame_crtc_master_sync(dc->current_state);
+ dc_trigger_sync(dc, dc->current_state);
+ }
+ mutex_unlock(&adev->dm.dc_lock);
+}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index dd1559c743c2..34f6369bf51f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -149,6 +149,8 @@ struct amdgpu_dm_backlight_caps {
* @cached_state: Caches device atomic state for suspend/resume
* @cached_dc_state: Cached state of content streams
* @compressor: Frame buffer compression buffer. See &struct dm_comressor_info
+ * @force_timing_sync: set via debugfs. When set, indicates that all connected
+ * displays will be forced to synchronize.
*/
struct amdgpu_display_manager {
@@ -340,6 +342,20 @@ struct amdgpu_display_manager {
* fake encoders used for DP MST.
*/
struct amdgpu_encoder mst_encoders[AMDGPU_DM_MAX_CRTC];
+ bool force_timing_sync;
+};
+
+enum dsc_clock_force_state {
+ DSC_CLK_FORCE_DEFAULT = 0,
+ DSC_CLK_FORCE_ENABLE,
+ DSC_CLK_FORCE_DISABLE,
+};
+
+struct dsc_preferred_settings {
+ enum dsc_clock_force_state dsc_force_enable;
+ uint32_t dsc_num_slices_v;
+ uint32_t dsc_num_slices_h;
+ uint32_t dsc_bits_per_pixel;
};
struct amdgpu_dm_connector {
@@ -389,6 +405,7 @@ struct amdgpu_dm_connector {
uint32_t debugfs_dpcd_size;
#endif
bool force_yuv420_output;
+ struct dsc_preferred_settings dsc_settings;
};
#define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base)
@@ -403,6 +420,8 @@ struct dc_plane_state;
struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
+ uint64_t tiling_flags;
+ bool tmz_surface;
};
struct dm_crtc_state {
@@ -423,7 +442,6 @@ struct dm_crtc_state {
bool vrr_supported;
struct mod_freesync_config freesync_config;
- struct mod_vrr_params vrr_params;
struct dc_info_packet vrr_infopacket;
int abm_level;
@@ -485,6 +503,8 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
struct edid *edid);
+void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
+
#define MAX_COLOR_LUT_ENTRIES 4096
/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index b321ff654df4..5df05f0d18bc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -308,8 +308,7 @@ static int __set_input_tf(struct dc_transfer_func *func,
int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
{
struct dc_stream_state *stream = crtc->stream;
- struct amdgpu_device *adev =
- (struct amdgpu_device *)crtc->base.state->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
bool has_rom = adev->asic_type <= CHIP_RAVEN;
struct drm_color_ctm *ctm = NULL;
const struct drm_color_lut *degamma_lut, *regamma_lut;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index eaad9099bc0b..d0699e98db92 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -101,7 +101,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
struct dm_crtc_state *dm_crtc_state,
enum amdgpu_dm_pipe_crc_source source)
{
- struct amdgpu_device *adev = crtc->dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dc_stream_state *stream_state = dm_crtc_state->stream;
bool enable = amdgpu_dm_is_valid_crc_source(source);
int ret = 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index e5a6d9115949..8cd646eef096 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -49,6 +49,10 @@ struct dmub_debugfs_trace_entry {
uint32_t param1;
};
+static inline const char *yesno(bool v)
+{
+ return v ? "yes" : "no";
+}
/* parse_write_buffer_into_params - Helper function to parse debugfs write buffer into an array
*
@@ -107,7 +111,6 @@ static int parse_write_buffer_into_params(char *wr_buf, uint32_t wr_buf_size,
if (*param_nums > max_param_num)
*param_nums = max_param_num;
-;
wr_buf_ptr = wr_buf; /* reset buf pointer */
wr_buf_count = 0; /* number of char already checked */
@@ -261,7 +264,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
if (!wr_buf)
return -ENOSPC;
- if (parse_write_buffer_into_params(wr_buf, wr_buf_size,
+ if (parse_write_buffer_into_params(wr_buf, size,
(long *)param, buf,
max_param_num,
&param_nums)) {
@@ -420,7 +423,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf,
if (!wr_buf)
return -ENOSPC;
- if (parse_write_buffer_into_params(wr_buf, wr_buf_size,
+ if (parse_write_buffer_into_params(wr_buf, size,
(long *)param, buf,
max_param_num,
&param_nums)) {
@@ -572,7 +575,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us
if (!wr_buf)
return -ENOSPC;
- if (parse_write_buffer_into_params(wr_buf, wr_buf_size,
+ if (parse_write_buffer_into_params(wr_buf, size,
(long *)param, buf,
max_param_num,
&param_nums)) {
@@ -905,7 +908,7 @@ static ssize_t dp_dpcd_address_write(struct file *f, const char __user *buf,
struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
if (size < sizeof(connector->debugfs_dpcd_address))
- return 0;
+ return -EINVAL;
r = copy_from_user(&connector->debugfs_dpcd_address,
buf, sizeof(connector->debugfs_dpcd_address));
@@ -920,7 +923,7 @@ static ssize_t dp_dpcd_size_write(struct file *f, const char __user *buf,
struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
if (size < sizeof(connector->debugfs_dpcd_size))
- return 0;
+ return -EINVAL;
r = copy_from_user(&connector->debugfs_dpcd_size,
buf, sizeof(connector->debugfs_dpcd_size));
@@ -940,8 +943,8 @@ static ssize_t dp_dpcd_data_write(struct file *f, const char __user *buf,
struct dc_link *link = connector->dc_link;
uint32_t write_size = connector->debugfs_dpcd_size;
- if (size < write_size)
- return 0;
+ if (!write_size || size < write_size)
+ return -EINVAL;
data = kzalloc(write_size, GFP_KERNEL);
if (!data)
@@ -964,7 +967,7 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf,
struct dc_link *link = connector->dc_link;
uint32_t read_size = connector->debugfs_dpcd_size;
- if (size < read_size)
+ if (!read_size || size < read_size)
return 0;
data = kzalloc(read_size, GFP_KERNEL);
@@ -980,6 +983,190 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf,
return read_size - r;
}
+/* function: Read link's DSC & FEC capabilities
+ *
+ *
+ * Access it with the following command (you need to specify
+ * connector like DP-1):
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dp_dsc_fec_support
+ *
+ */
+static int dp_dsc_fec_support_show(struct seq_file *m, void *data)
+{
+ struct drm_connector *connector = m->private;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+ int ret = 0;
+ bool try_again = false;
+ bool is_fec_supported = false;
+ bool is_dsc_supported = false;
+ struct dpcd_caps dpcd_caps;
+
+ drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
+ do {
+ try_again = false;
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);
+ if (ret) {
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret) {
+ try_again = true;
+ continue;
+ }
+ }
+ break;
+ }
+ if (connector->status != connector_status_connected) {
+ ret = -ENODEV;
+ break;
+ }
+ dpcd_caps = aconnector->dc_link->dpcd_caps;
+ if (aconnector->port) {
+ /* aconnector sets dsc_aux during get_modes call
+ * if MST connector has it means it can either
+ * enable DSC on the sink device or on MST branch
+ * its connected to.
+ */
+ if (aconnector->dsc_aux) {
+ is_fec_supported = true;
+ is_dsc_supported = true;
+ }
+ } else {
+ is_fec_supported = dpcd_caps.fec_cap.raw & 0x1;
+ is_dsc_supported = dpcd_caps.dsc_caps.dsc_basic_caps.raw[0] & 0x1;
+ }
+ } while (try_again);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ seq_printf(m, "FEC_Sink_Support: %s\n", yesno(is_fec_supported));
+ seq_printf(m, "DSC_Sink_Support: %s\n", yesno(is_dsc_supported));
+
+ return ret;
+}
+
+/* function: Trigger virtual HPD redetection on connector
+ *
+ * This function will perform link rediscovery, link disable
+ * and enable, and dm connector state update.
+ *
+ * Retrigger HPD on an existing connector by echoing 1 into
+ * its respectful "trigger_hotplug" debugfs entry:
+ *
+ * echo 1 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug
+ *
+ * This function can perform HPD unplug:
+ *
+ * echo 0 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug
+ *
+ */
+static ssize_t dp_trigger_hotplug(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
+ struct drm_connector *connector = &aconnector->base;
+ struct dc_link *link = NULL;
+ struct drm_device *dev = connector->dev;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ char *wr_buf = NULL;
+ uint32_t wr_buf_size = 42;
+ int max_param_num = 1;
+ long param[1] = {0};
+ uint8_t param_nums = 0;
+
+ if (!aconnector || !aconnector->dc_link)
+ return -EINVAL;
+
+ if (size == 0)
+ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+
+ if (!wr_buf) {
+ DRM_DEBUG_DRIVER("no memory to allocate write buffer\n");
+ return -ENOSPC;
+ }
+
+ if (parse_write_buffer_into_params(wr_buf, size,
+ (long *)param, buf,
+ max_param_num,
+ &param_nums)) {
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param_nums <= 0) {
+ DRM_DEBUG_DRIVER("user data not be read\n");
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param[0] == 1) {
+ mutex_lock(&aconnector->hpd_lock);
+
+ if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type) &&
+ new_connection_type != dc_connection_none)
+ goto unlock;
+
+ if (!dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD))
+ goto unlock;
+
+ amdgpu_dm_update_connector_after_detect(aconnector);
+
+ drm_modeset_lock_all(dev);
+ dm_restore_drm_connector_state(dev, connector);
+ drm_modeset_unlock_all(dev);
+
+ drm_kms_helper_hotplug_event(dev);
+ } else if (param[0] == 0) {
+ if (!aconnector->dc_link)
+ goto unlock;
+
+ link = aconnector->dc_link;
+
+ if (link->local_sink) {
+ dc_sink_release(link->local_sink);
+ link->local_sink = NULL;
+ }
+
+ link->dpcd_sink_count = 0;
+ link->type = dc_connection_none;
+ link->dongle_max_pix_clk = 0;
+
+ amdgpu_dm_update_connector_after_detect(aconnector);
+
+ drm_modeset_lock_all(dev);
+ dm_restore_drm_connector_state(dev, connector);
+ drm_modeset_unlock_all(dev);
+
+ drm_kms_helper_hotplug_event(dev);
+ }
+
+unlock:
+ mutex_unlock(&aconnector->hpd_lock);
+
+ kfree(wr_buf);
+ return size;
+}
+
+/* function: read DSC status on the connector
+ *
+ * The read function: dp_dsc_clock_en_read
+ * returns current status of DSC clock on the connector.
+ * The return is a boolean flag: 1 or 0.
+ *
+ * Access it with the following command (you need to specify
+ * connector like DP-1):
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_clock_en
+ *
+ * Expected output:
+ * 1 - means that DSC is currently enabled
+ * 0 - means that DSC is disabled
+ */
static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1037,6 +1224,105 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
return result;
}
+/* function: write force DSC on the connector
+ *
+ * The write function: dp_dsc_clock_en_write
+ * enables to force DSC on the connector.
+ * User can write to either force enable or force disable DSC
+ * on the next modeset or set it to driver default
+ *
+ * Accepted inputs:
+ * 0 - default DSC enablement policy
+ * 1 - force enable DSC on the connector
+ * 2 - force disable DSC on the connector (might cause fail in atomic_check)
+ *
+ * Writing DSC settings is done with the following command:
+ * - To force enable DSC (you need to specify
+ * connector like DP-1):
+ *
+ * echo 0x1 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en
+ *
+ * - To return to default state set the flag to zero and
+ * let driver deal with DSC automatically
+ * (you need to specify connector like DP-1):
+ *
+ * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en
+ *
+ */
+static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
+ struct pipe_ctx *pipe_ctx;
+ int i;
+ char *wr_buf = NULL;
+ uint32_t wr_buf_size = 42;
+ int max_param_num = 1;
+ long param[1] = {0};
+ uint8_t param_nums = 0;
+
+ if (size == 0)
+ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+
+ if (!wr_buf) {
+ DRM_DEBUG_DRIVER("no memory to allocate write buffer\n");
+ return -ENOSPC;
+ }
+
+ if (parse_write_buffer_into_params(wr_buf, size,
+ (long *)param, buf,
+ max_param_num,
+ &param_nums)) {
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param_nums <= 0) {
+ DRM_DEBUG_DRIVER("user data not be read\n");
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx && pipe_ctx->stream &&
+ pipe_ctx->stream->link == aconnector->dc_link)
+ break;
+ }
+
+ if (!pipe_ctx || !pipe_ctx->stream)
+ goto done;
+
+ if (param[0] == 1)
+ aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE;
+ else if (param[0] == 2)
+ aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_DISABLE;
+ else
+ aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_DEFAULT;
+
+done:
+ kfree(wr_buf);
+ return size;
+}
+
+/* function: read DSC slice width parameter on the connector
+ *
+ * The read function: dp_dsc_slice_width_read
+ * returns dsc slice width used in the current configuration
+ * The return is an integer: 0 or other positive number
+ *
+ * Access the status with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_width
+ *
+ * 0 - means that DSC is disabled
+ *
+ * Any other number more than zero represents the
+ * slice width currently used by DSC in pixels
+ *
+ */
static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1094,6 +1380,103 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
return result;
}
+/* function: write DSC slice width parameter
+ *
+ * The write function: dp_dsc_slice_width_write
+ * overwrites automatically generated DSC configuration
+ * of slice width.
+ *
+ * The user has to write the slice width divisible by the
+ * picture width.
+ *
+ * Also the user has to write width in hexidecimal
+ * rather than in decimal.
+ *
+ * Writing DSC settings is done with the following command:
+ * - To force overwrite slice width: (example sets to 1920 pixels)
+ *
+ * echo 0x780 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width
+ *
+ * - To stop overwriting and let driver find the optimal size,
+ * set the width to zero:
+ *
+ * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width
+ *
+ */
+static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
+ struct pipe_ctx *pipe_ctx;
+ int i;
+ char *wr_buf = NULL;
+ uint32_t wr_buf_size = 42;
+ int max_param_num = 1;
+ long param[1] = {0};
+ uint8_t param_nums = 0;
+
+ if (size == 0)
+ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+
+ if (!wr_buf) {
+ DRM_DEBUG_DRIVER("no memory to allocate write buffer\n");
+ return -ENOSPC;
+ }
+
+ if (parse_write_buffer_into_params(wr_buf, size,
+ (long *)param, buf,
+ max_param_num,
+ &param_nums)) {
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param_nums <= 0) {
+ DRM_DEBUG_DRIVER("user data not be read\n");
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx && pipe_ctx->stream &&
+ pipe_ctx->stream->link == aconnector->dc_link)
+ break;
+ }
+
+ if (!pipe_ctx || !pipe_ctx->stream)
+ goto done;
+
+ if (param[0] > 0)
+ aconnector->dsc_settings.dsc_num_slices_h = DIV_ROUND_UP(
+ pipe_ctx->stream->timing.h_addressable,
+ param[0]);
+ else
+ aconnector->dsc_settings.dsc_num_slices_h = 0;
+
+done:
+ kfree(wr_buf);
+ return size;
+}
+
+/* function: read DSC slice height parameter on the connector
+ *
+ * The read function: dp_dsc_slice_height_read
+ * returns dsc slice height used in the current configuration
+ * The return is an integer: 0 or other positive number
+ *
+ * Access the status with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_height
+ *
+ * 0 - means that DSC is disabled
+ *
+ * Any other number more than zero represents the
+ * slice height currently used by DSC in pixels
+ *
+ */
static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1151,6 +1534,99 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
return result;
}
+/* function: write DSC slice height parameter
+ *
+ * The write function: dp_dsc_slice_height_write
+ * overwrites automatically generated DSC configuration
+ * of slice height.
+ *
+ * The user has to write the slice height divisible by the
+ * picture height.
+ *
+ * Also the user has to write height in hexidecimal
+ * rather than in decimal.
+ *
+ * Writing DSC settings is done with the following command:
+ * - To force overwrite slice height (example sets to 128 pixels):
+ *
+ * echo 0x80 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height
+ *
+ * - To stop overwriting and let driver find the optimal size,
+ * set the height to zero:
+ *
+ * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height
+ *
+ */
+static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
+ struct pipe_ctx *pipe_ctx;
+ int i;
+ char *wr_buf = NULL;
+ uint32_t wr_buf_size = 42;
+ int max_param_num = 1;
+ uint8_t param_nums = 0;
+ long param[1] = {0};
+
+ if (size == 0)
+ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+
+ if (!wr_buf) {
+ DRM_DEBUG_DRIVER("no memory to allocate write buffer\n");
+ return -ENOSPC;
+ }
+
+ if (parse_write_buffer_into_params(wr_buf, size,
+ (long *)param, buf,
+ max_param_num,
+ &param_nums)) {
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param_nums <= 0) {
+ DRM_DEBUG_DRIVER("user data not be read\n");
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx && pipe_ctx->stream &&
+ pipe_ctx->stream->link == aconnector->dc_link)
+ break;
+ }
+
+ if (!pipe_ctx || !pipe_ctx->stream)
+ goto done;
+
+ if (param[0] > 0)
+ aconnector->dsc_settings.dsc_num_slices_v = DIV_ROUND_UP(
+ pipe_ctx->stream->timing.v_addressable,
+ param[0]);
+ else
+ aconnector->dsc_settings.dsc_num_slices_v = 0;
+
+done:
+ kfree(wr_buf);
+ return size;
+}
+
+/* function: read DSC target rate on the connector in bits per pixel
+ *
+ * The read function: dp_dsc_bits_per_pixel_read
+ * returns target rate of compression in bits per pixel
+ * The return is an integer: 0 or other positive integer
+ *
+ * Access it with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel
+ *
+ * 0 - means that DSC is disabled
+ */
static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1208,6 +1684,94 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
return result;
}
+/* function: write DSC target rate in bits per pixel
+ *
+ * The write function: dp_dsc_bits_per_pixel_write
+ * overwrites automatically generated DSC configuration
+ * of DSC target bit rate.
+ *
+ * Also the user has to write bpp in hexidecimal
+ * rather than in decimal.
+ *
+ * Writing DSC settings is done with the following command:
+ * - To force overwrite rate (example sets to 256 bpp x 1/16):
+ *
+ * echo 0x100 > /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel
+ *
+ * - To stop overwriting and let driver find the optimal rate,
+ * set the rate to zero:
+ *
+ * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel
+ *
+ */
+static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
+ struct pipe_ctx *pipe_ctx;
+ int i;
+ char *wr_buf = NULL;
+ uint32_t wr_buf_size = 42;
+ int max_param_num = 1;
+ uint8_t param_nums = 0;
+ long param[1] = {0};
+
+ if (size == 0)
+ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+
+ if (!wr_buf) {
+ DRM_DEBUG_DRIVER("no memory to allocate write buffer\n");
+ return -ENOSPC;
+ }
+
+ if (parse_write_buffer_into_params(wr_buf, size,
+ (long *)param, buf,
+ max_param_num,
+ &param_nums)) {
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ if (param_nums <= 0) {
+ DRM_DEBUG_DRIVER("user data not be read\n");
+ kfree(wr_buf);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx && pipe_ctx->stream &&
+ pipe_ctx->stream->link == aconnector->dc_link)
+ break;
+ }
+
+ if (!pipe_ctx || !pipe_ctx->stream)
+ goto done;
+
+ aconnector->dsc_settings.dsc_bits_per_pixel = param[0];
+
+done:
+ kfree(wr_buf);
+ return size;
+}
+
+/* function: read DSC picture width parameter on the connector
+ *
+ * The read function: dp_dsc_pic_width_read
+ * returns dsc picture width used in the current configuration
+ * It is the same as h_addressable of the current
+ * display's timing
+ * The return is an integer: 0 or other positive integer
+ * If 0 then DSC is disabled.
+ *
+ * Access it with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_pic_width
+ *
+ * 0 - means that DSC is disabled
+ */
static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1322,6 +1886,21 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf,
return result;
}
+/* function: read DSC chunk size parameter on the connector
+ *
+ * The read function: dp_dsc_chunk_size_read
+ * returns dsc chunk size set in the current configuration
+ * The value is calculated automatically by DSC code
+ * and depends on slice parameters and bpp target rate
+ * The return is an integer: 0 or other positive integer
+ * If 0 then DSC is disabled.
+ *
+ * Access it with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_chunk_size
+ *
+ * 0 - means that DSC is disabled
+ */
static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1379,6 +1958,21 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
return result;
}
+/* function: read DSC slice bpg offset on the connector
+ *
+ * The read function: dp_dsc_slice_bpg_offset_read
+ * returns dsc bpg slice offset set in the current configuration
+ * The value is calculated automatically by DSC code
+ * and depends on slice parameters and bpp target rate
+ * The return is an integer: 0 or other positive integer
+ * If 0 then DSC is disabled.
+ *
+ * Access it with the following command:
+ *
+ * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_bpg_offset
+ *
+ * 0 - means that DSC is disabled
+ */
static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
@@ -1436,6 +2030,7 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
return result;
}
+DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support);
DEFINE_SHOW_ATTRIBUTE(dmub_fw_state);
DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer);
DEFINE_SHOW_ATTRIBUTE(output_bpc);
@@ -1446,24 +2041,28 @@ DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability);
static const struct file_operations dp_dsc_clock_en_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_dsc_clock_en_read,
+ .write = dp_dsc_clock_en_write,
.llseek = default_llseek
};
static const struct file_operations dp_dsc_slice_width_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_dsc_slice_width_read,
+ .write = dp_dsc_slice_width_write,
.llseek = default_llseek
};
static const struct file_operations dp_dsc_slice_height_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_dsc_slice_height_read,
+ .write = dp_dsc_slice_height_write,
.llseek = default_llseek
};
static const struct file_operations dp_dsc_bits_per_pixel_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_dsc_bits_per_pixel_read,
+ .write = dp_dsc_bits_per_pixel_write,
.llseek = default_llseek
};
@@ -1491,6 +2090,12 @@ static const struct file_operations dp_dsc_slice_bpg_offset_debugfs_fops = {
.llseek = default_llseek
};
+static const struct file_operations dp_trigger_hotplug_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .write = dp_trigger_hotplug,
+ .llseek = default_llseek
+};
+
static const struct file_operations dp_link_settings_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_link_settings_read,
@@ -1541,6 +2146,7 @@ static const struct {
const struct file_operations *fops;
} dp_debugfs_entries[] = {
{"link_settings", &dp_link_settings_debugfs_fops},
+ {"trigger_hotplug", &dp_trigger_hotplug_debugfs_fops},
{"phy_settings", &dp_phy_settings_debugfs_fop},
{"test_pattern", &dp_phy_test_pattern_fops},
#ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -1557,7 +2163,8 @@ static const struct {
{"dsc_pic_width", &dp_dsc_pic_width_debugfs_fops},
{"dsc_pic_height", &dp_dsc_pic_height_debugfs_fops},
{"dsc_chunk_size", &dp_dsc_chunk_size_debugfs_fops},
- {"dsc_slice_bpg", &dp_dsc_slice_bpg_offset_debugfs_fops}
+ {"dsc_slice_bpg", &dp_dsc_slice_bpg_offset_debugfs_fops},
+ {"dp_dsc_fec_support", &dp_dsc_fec_support_fops}
};
#ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -1721,7 +2328,7 @@ static int current_backlight_read(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *dev = node->minor->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_display_manager *dm = &adev->dm;
unsigned int backlight = dc_link_get_backlight_level(dm->backlight_link);
@@ -1739,7 +2346,7 @@ static int target_backlight_read(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *dev = node->minor->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_display_manager *dm = &adev->dm;
unsigned int backlight = dc_link_get_target_backlight_pwm(dm->backlight_link);
@@ -1778,6 +2385,38 @@ static const struct drm_info_list amdgpu_dm_debugfs_list[] = {
};
/*
+ * Sets the force_timing_sync debug optino from the given string.
+ * All connected displays will be force synchronized immediately.
+ * Usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_force_timing_sync
+ */
+static int force_timing_sync_set(void *data, u64 val)
+{
+ struct amdgpu_device *adev = data;
+
+ adev->dm.force_timing_sync = (bool)val;
+
+ amdgpu_dm_trigger_timing_sync(adev_to_drm(adev));
+
+ return 0;
+}
+
+/*
+ * Gets the force_timing_sync debug option value into the given buffer.
+ * Usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_force_timing_sync
+ */
+static int force_timing_sync_get(void *data, u64 *val)
+{
+ struct amdgpu_device *adev = data;
+
+ *val = adev->dm.force_timing_sync;
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(force_timing_sync_ops, force_timing_sync_get,
+ force_timing_sync_set, "%llu\n");
+
+/*
* Sets the DC visual confirm debug option from the given string.
* Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_visual_confirm
*/
@@ -1815,7 +2454,7 @@ int dtn_debugfs_init(struct amdgpu_device *adev)
.llseek = default_llseek
};
- struct drm_minor *minor = adev->ddev->primary;
+ struct drm_minor *minor = adev_to_drm(adev)->primary;
struct dentry *root = minor->debugfs_root;
int ret;
@@ -1836,5 +2475,8 @@ int dtn_debugfs_init(struct amdgpu_device *adev)
debugfs_create_file_unsafe("amdgpu_dm_dmub_fw_state", 0644, root,
adev, &dmub_fw_state_fops);
+ debugfs_create_file_unsafe("amdgpu_dm_force_timing_sync", 0644, root,
+ adev, &force_timing_sync_ops);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index cbcf504f73a5..357778556b06 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -719,7 +719,7 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
*/
void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
{
- struct drm_device *dev = adev->ddev;
+ struct drm_device *dev = adev_to_drm(adev);
struct drm_connector *connector;
struct drm_connector_list_iter iter;
@@ -755,7 +755,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
*/
void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
{
- struct drm_device *dev = adev->ddev;
+ struct drm_device *dev = adev_to_drm(adev);
struct drm_connector *connector;
struct drm_connector_list_iter iter;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h
new file mode 100644
index 000000000000..45825a34f8eb
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __AMDGPU_DM_IRQ_PARAMS_H__
+#define __AMDGPU_DM_IRQ_PARAMS_H__
+
+struct dm_irq_params {
+ u32 last_flip_vblank;
+ struct mod_vrr_params vrr_params;
+ struct dc_stream_state *stream;
+ int active_planes;
+ struct mod_freesync_config freesync_config;
+};
+
+#endif /* __AMDGPU_DM_IRQ_PARAMS_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 336aaa09be46..eee19edeeee5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -26,6 +26,7 @@
#include <linux/version.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_dp_helper.h>
#include "dm_services.h"
#include "amdgpu.h"
#include "amdgpu_dm.h"
@@ -158,7 +159,20 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
u8 dsc_caps[16] = { 0 };
aconnector->dsc_aux = drm_dp_mst_dsc_aux_for_port(port);
+#if defined(CONFIG_HP_HOOK_WORKAROUND)
+ /*
+ * drm_dp_mst_dsc_aux_for_port() will return NULL for certain configs
+ * because it only check the dsc/fec caps of the "port variable" and not the dock
+ *
+ * This case will return NULL: DSC capabe MST dock connected to a non fec/dsc capable display
+ *
+ * Workaround: explicitly check the use case above and use the mst dock's aux as dsc_aux
+ *
+ */
+ if (!aconnector->dsc_aux && !port->parent->port_parent)
+ aconnector->dsc_aux = &aconnector->mst_port->dm_dp_aux.aux;
+#endif
if (!aconnector->dsc_aux)
return false;
@@ -241,7 +255,7 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector,
struct drm_connector_state *connector_state)
{
struct drm_device *dev = connector->dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc);
return &adev->dm.mst_encoders[acrtc->crtc_id].base;
@@ -310,7 +324,7 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
void
dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev)
{
- struct drm_device *dev = adev->ddev;
+ struct drm_device *dev = adev_to_drm(adev);
int i;
for (i = 0; i < adev->dm.display_indexes_num; i++) {
@@ -337,7 +351,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
{
struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
- struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
int i;
@@ -426,11 +440,13 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
aconnector->mst_mgr.cbs = &dm_mst_cbs;
drm_dp_mst_topology_mgr_init(
&aconnector->mst_mgr,
- dm->adev->ddev,
+ adev_to_drm(dm->adev),
&aconnector->dm_dp_aux.aux,
16,
4,
aconnector->connector_id);
+
+ drm_connector_attach_dp_subconnector_property(&aconnector->base);
}
int dm_mst_get_pbn_divider(struct dc_link *link)
@@ -450,6 +466,10 @@ struct dsc_mst_fairness_params {
struct dc_dsc_bw_range bw_range;
bool compression_possible;
struct drm_dp_mst_port *port;
+ enum dsc_clock_force_state clock_force_enable;
+ uint32_t num_slices_h;
+ uint32_t num_slices_v;
+ uint32_t bpp_overwrite;
};
struct dsc_mst_fairness_vars {
@@ -483,7 +503,17 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p
params[i].timing,
&params[i].timing->dsc_cfg)) {
params[i].timing->flags.DSC = 1;
- params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16;
+
+ if (params[i].bpp_overwrite)
+ params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite;
+ else
+ params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16;
+
+ if (params[i].num_slices_h)
+ params[i].timing->dsc_cfg.num_slices_h = params[i].num_slices_h;
+
+ if (params[i].num_slices_v)
+ params[i].timing->dsc_cfg.num_slices_v = params[i].num_slices_v;
} else {
params[i].timing->flags.DSC = 0;
}
@@ -615,7 +645,9 @@ static void try_disable_dsc(struct drm_atomic_state *state,
int remaining_to_try = 0;
for (i = 0; i < count; i++) {
- if (vars[i].dsc_enabled && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16) {
+ if (vars[i].dsc_enabled
+ && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16
+ && params[i].clock_force_enable == DSC_CLK_FORCE_DEFAULT) {
kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps;
tried[i] = false;
remaining_to_try += 1;
@@ -676,6 +708,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
struct dsc_mst_fairness_vars vars[MAX_PIPES];
struct amdgpu_dm_connector *aconnector;
int count = 0;
+ bool debugfs_overwrite = false;
memset(params, 0, sizeof(params));
@@ -694,6 +727,12 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
params[count].sink = stream->sink;
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
params[count].port = aconnector->port;
+ params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable;
+ if (params[count].clock_force_enable == DSC_CLK_FORCE_ENABLE)
+ debugfs_overwrite = true;
+ params[count].num_slices_h = aconnector->dsc_settings.dsc_num_slices_h;
+ params[count].num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
+ params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
dc_dsc_get_policy_for_timing(params[count].timing, &dsc_policy);
if (!dc_dsc_compute_bandwidth_range(
@@ -719,14 +758,14 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
dm_mst_get_pbn_divider(dc_link)) < 0)
return false;
}
- if (!drm_dp_mst_atomic_check(state)) {
+ if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) {
set_dsc_configs_from_fairness_vars(params, vars, count);
return true;
}
/* Try max compression */
for (i = 0; i < count; i++) {
- if (params[i].compression_possible) {
+ if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) {
vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
vars[i].dsc_enabled = true;
vars[i].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
index c5f2216e59c4..6e575ffe34d0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
@@ -592,9 +592,6 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
pp_funcs->set_watermarks_for_clocks_ranges(pp_handle,
&wm_with_clock_ranges);
- else if (adev->smu.ppt_funcs)
- smu_set_watermarks_for_clock_ranges(&adev->smu,
- &wm_with_clock_ranges);
}
void pp_rv_set_pme_wa_enable(struct pp_smu *pp)
@@ -667,49 +664,8 @@ static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges;
- struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks =
- wm_with_clock_ranges.wm_dmif_clocks_ranges;
- struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks =
- wm_with_clock_ranges.wm_mcif_clocks_ranges;
- int32_t i;
- wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets;
- wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets;
-
- for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) {
- if (ranges->reader_wm_sets[i].wm_inst > 3)
- wm_dce_clocks[i].wm_set_id = WM_SET_A;
- else
- wm_dce_clocks[i].wm_set_id =
- ranges->reader_wm_sets[i].wm_inst;
- wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000;
- wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000;
- wm_dce_clocks[i].wm_max_mem_clk_in_khz =
- ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000;
- wm_dce_clocks[i].wm_min_mem_clk_in_khz =
- ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000;
- }
-
- for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) {
- if (ranges->writer_wm_sets[i].wm_inst > 3)
- wm_soc_clocks[i].wm_set_id = WM_SET_A;
- else
- wm_soc_clocks[i].wm_set_id =
- ranges->writer_wm_sets[i].wm_inst;
- wm_soc_clocks[i].wm_max_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000;
- wm_soc_clocks[i].wm_min_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000;
- wm_soc_clocks[i].wm_max_mem_clk_in_khz =
- ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000;
- wm_soc_clocks[i].wm_min_mem_clk_in_khz =
- ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
- }
-
- smu_set_watermarks_for_clock_ranges(&adev->smu, &wm_with_clock_ranges);
+ smu_set_watermarks_for_clock_ranges(&adev->smu, ranges);
return PP_SMU_RESULT_OK;
}
@@ -810,7 +766,7 @@ pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz)
}
static enum pp_smu_status pp_nv_set_pstate_handshake_support(
- struct pp_smu *pp, BOOLEAN pstate_handshake_supported)
+ struct pp_smu *pp, bool pstate_handshake_supported)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
@@ -920,60 +876,8 @@ static enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- struct smu_context *smu = &adev->smu;
- struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges;
- struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks =
- wm_with_clock_ranges.wm_dmif_clocks_ranges;
- struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks =
- wm_with_clock_ranges.wm_mcif_clocks_ranges;
- int32_t i;
-
- if (!smu->ppt_funcs)
- return PP_SMU_RESULT_UNSUPPORTED;
-
- wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets;
- wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets;
-
- for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) {
- if (ranges->reader_wm_sets[i].wm_inst > 3)
- wm_dce_clocks[i].wm_set_id = WM_SET_A;
- else
- wm_dce_clocks[i].wm_set_id =
- ranges->reader_wm_sets[i].wm_inst;
-
- wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].min_drain_clk_mhz;
-
- wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].max_drain_clk_mhz;
-
- wm_dce_clocks[i].wm_min_mem_clk_in_khz =
- ranges->reader_wm_sets[i].min_fill_clk_mhz;
-
- wm_dce_clocks[i].wm_max_mem_clk_in_khz =
- ranges->reader_wm_sets[i].max_fill_clk_mhz;
- }
-
- for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) {
- if (ranges->writer_wm_sets[i].wm_inst > 3)
- wm_soc_clocks[i].wm_set_id = WM_SET_A;
- else
- wm_soc_clocks[i].wm_set_id =
- ranges->writer_wm_sets[i].wm_inst;
- wm_soc_clocks[i].wm_min_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].min_fill_clk_mhz;
-
- wm_soc_clocks[i].wm_max_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].max_fill_clk_mhz;
-
- wm_soc_clocks[i].wm_min_mem_clk_in_khz =
- ranges->writer_wm_sets[i].min_drain_clk_mhz;
-
- wm_soc_clocks[i].wm_max_mem_clk_in_khz =
- ranges->writer_wm_sets[i].max_drain_clk_mhz;
- }
- smu_set_watermarks_for_clock_ranges(&adev->smu, &wm_with_clock_ranges);
+ smu_set_watermarks_for_clock_ranges(&adev->smu, ranges);
return PP_SMU_RESULT_OK;
}