Commit 49e37ba0 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux into drm-next

Various fixes for DC for 4.15.

* 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux:
  drm/amd/display: fix MST link training fail division by 0
  drm/amd/display: Fix formatting for null pointer dereference fix
  drm/amd/display: Remove dangling planes on dc commit state
  drm/amd/display: add flip_immediate to commit update for stream
  drm/amd/display: Miss register MST encoder cbs
  drm/amd/display: Fix warnings on S3 resume
  drm/amd/display: use num_timing_generator instead of pipe_count
  drm/amd/display: use configurable FBC option in dm
  drm/amd/display: fix AZ clock not enabled before program AZ endpoint
  amdgpu/dm: Don't use DRM_ERROR in amdgpu_dm_atomic_check
parents 4479ed41 00f713c6
...@@ -344,7 +344,7 @@ static void hotplug_notify_work_func(struct work_struct *work) ...@@ -344,7 +344,7 @@ static void hotplug_notify_work_func(struct work_struct *work)
drm_kms_helper_hotplug_event(dev); drm_kms_helper_hotplug_event(dev);
} }
#ifdef ENABLE_FBC #if defined(CONFIG_DRM_AMD_DC_FBC)
#include "dal_asic_id.h" #include "dal_asic_id.h"
/* Allocate memory for FBC compressed data */ /* Allocate memory for FBC compressed data */
/* TODO: Dynamic allocation */ /* TODO: Dynamic allocation */
...@@ -422,7 +422,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) ...@@ -422,7 +422,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
else else
init_data.log_mask = DC_MIN_LOG_MASK; init_data.log_mask = DC_MIN_LOG_MASK;
#ifdef ENABLE_FBC #if defined(CONFIG_DRM_AMD_DC_FBC)
if (adev->family == FAMILY_CZ) if (adev->family == FAMILY_CZ)
amdgpu_dm_initialize_fbc(adev); amdgpu_dm_initialize_fbc(adev);
init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr; init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr;
...@@ -643,6 +643,11 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev) ...@@ -643,6 +643,11 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
struct drm_connector *connector; struct drm_connector *connector;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state; struct drm_crtc_state *new_crtc_state;
struct dm_crtc_state *dm_new_crtc_state;
struct drm_plane *plane;
struct drm_plane_state *new_plane_state;
struct dm_plane_state *dm_new_plane_state;
int ret = 0; int ret = 0;
int i; int i;
...@@ -681,6 +686,29 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev) ...@@ -681,6 +686,29 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i) for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i)
new_crtc_state->active_changed = true; new_crtc_state->active_changed = true;
/*
* atomic_check is expected to create the dc states. We need to release
* them here, since they were duplicated as part of the suspend
* procedure.
*/
for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i) {
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
if (dm_new_crtc_state->stream) {
WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
dc_stream_release(dm_new_crtc_state->stream);
dm_new_crtc_state->stream = NULL;
}
}
for_each_new_plane_in_state(adev->dm.cached_state, plane, new_plane_state, i) {
dm_new_plane_state = to_dm_plane_state(new_plane_state);
if (dm_new_plane_state->dc_state) {
WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
dc_plane_state_release(dm_new_plane_state->dc_state);
dm_new_plane_state->dc_state = NULL;
}
}
ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state); ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state);
drm_atomic_state_put(adev->dm.cached_state); drm_atomic_state_put(adev->dm.cached_state);
...@@ -4662,10 +4690,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4662,10 +4690,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
bool lock_and_validation_needed = false; bool lock_and_validation_needed = false;
ret = drm_atomic_helper_check_modeset(dev, state); ret = drm_atomic_helper_check_modeset(dev, state);
if (ret) { if (ret)
DRM_ERROR("Atomic state validation failed with error :%d !\n", ret); goto fail;
return ret;
}
/* /*
* legacy_cursor_update should be made false for SoC's having * legacy_cursor_update should be made false for SoC's having
...@@ -4782,11 +4808,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4782,11 +4808,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
fail: fail:
if (ret == -EDEADLK) if (ret == -EDEADLK)
DRM_DEBUG_DRIVER("Atomic check stopped due to to deadlock.\n"); DRM_DEBUG_DRIVER("Atomic check stopped to avoid deadlock.\n");
else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
DRM_DEBUG_DRIVER("Atomic check stopped due to to signal.\n"); DRM_DEBUG_DRIVER("Atomic check stopped due to signal.\n");
else else
DRM_ERROR("Atomic check failed with err: %d \n", ret); DRM_DEBUG_DRIVER("Atomic check failed with err: %d \n", ret);
return ret; return ret;
} }
......
...@@ -72,7 +72,7 @@ struct irq_list_head { ...@@ -72,7 +72,7 @@ struct irq_list_head {
struct work_struct work; struct work_struct work;
}; };
#ifdef ENABLE_FBC #if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info { struct dm_comressor_info {
void *cpu_addr; void *cpu_addr;
struct amdgpu_bo *bo_ptr; struct amdgpu_bo *bo_ptr;
...@@ -142,7 +142,7 @@ struct amdgpu_display_manager { ...@@ -142,7 +142,7 @@ struct amdgpu_display_manager {
* Caches device atomic state for suspend/resume * Caches device atomic state for suspend/resume
*/ */
struct drm_atomic_state *cached_state; struct drm_atomic_state *cached_state;
#ifdef ENABLE_FBC #if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info compressor; struct dm_comressor_info compressor;
#endif #endif
}; };
......
...@@ -245,6 +245,16 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs ...@@ -245,6 +245,16 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs
.best_encoder = dm_mst_best_encoder, .best_encoder = dm_mst_best_encoder,
}; };
static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
kfree(encoder);
}
static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
.destroy = amdgpu_dm_encoder_destroy,
};
static struct amdgpu_encoder * static struct amdgpu_encoder *
dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector) dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
{ {
...@@ -268,7 +278,7 @@ dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector) ...@@ -268,7 +278,7 @@ dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
drm_encoder_init( drm_encoder_init(
dev, dev,
&amdgpu_encoder->base, &amdgpu_encoder->base,
NULL, &amdgpu_dm_encoder_funcs,
DRM_MODE_ENCODER_DPMST, DRM_MODE_ENCODER_DPMST,
NULL); NULL);
......
...@@ -619,6 +619,39 @@ static bool construct(struct dc *dc, ...@@ -619,6 +619,39 @@ static bool construct(struct dc *dc,
return false; return false;
} }
static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
{
int i, j;
struct dc_state *dangling_context = dc_create_state();
struct dc_state *current_ctx;
if (dangling_context == NULL)
return;
dc_resource_state_copy_construct(dc->current_state, dangling_context);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct dc_stream_state *old_stream =
dc->current_state->res_ctx.pipe_ctx[i].stream;
bool should_disable = true;
for (j = 0; j < context->stream_count; j++) {
if (old_stream == context->streams[j]) {
should_disable = false;
break;
}
}
if (should_disable && old_stream) {
dc_rem_all_planes_for_stream(dc, old_stream, dangling_context);
dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context);
}
}
current_ctx = dc->current_state;
dc->current_state = dangling_context;
dc_release_state(current_ctx);
}
/******************************************************************************* /*******************************************************************************
* Public functions * Public functions
******************************************************************************/ ******************************************************************************/
...@@ -801,6 +834,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c ...@@ -801,6 +834,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
int i, j, k, l; int i, j, k, l;
struct dc_stream_state *dc_streams[MAX_STREAMS] = {0}; struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
disable_dangling_plane(dc, context);
for (i = 0; i < context->stream_count; i++) for (i = 0; i < context->stream_count; i++)
dc_streams[i] = context->streams[i]; dc_streams[i] = context->streams[i];
...@@ -830,8 +865,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c ...@@ -830,8 +865,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
} }
} }
CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}", CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
context->streams[i]->timing.h_addressable, context->streams[i]->timing.h_addressable,
context->streams[i]->timing.v_addressable, context->streams[i]->timing.v_addressable,
...@@ -1414,8 +1447,11 @@ void dc_commit_updates_for_stream(struct dc *dc, ...@@ -1414,8 +1447,11 @@ void dc_commit_updates_for_stream(struct dc *dc,
/* TODO: On flip we don't build the state, so it still has the /* TODO: On flip we don't build the state, so it still has the
* old address. Which is why we are updating the address here * old address. Which is why we are updating the address here
*/ */
if (srf_updates[i].flip_addr) if (srf_updates[i].flip_addr) {
surface->address = srf_updates[i].flip_addr->address; surface->address = srf_updates[i].flip_addr->address;
surface->flip_immediate = srf_updates[i].flip_addr->flip_immediate;
}
if (update_type >= UPDATE_TYPE_MED) { if (update_type >= UPDATE_TYPE_MED) {
for (j = 0; j < dc->res_pool->pipe_count; j++) { for (j = 0; j < dc->res_pool->pipe_count; j++) {
......
...@@ -2318,9 +2318,11 @@ void core_link_enable_stream( ...@@ -2318,9 +2318,11 @@ void core_link_enable_stream(
/* Abort stream enable *unless* the failure was due to /* Abort stream enable *unless* the failure was due to
* DP link training - some DP monitors will recover and * DP link training - some DP monitors will recover and
* show the stream anyway. * show the stream anyway. But MST displays can't proceed
* without link training.
*/ */
if (status != DC_FAIL_DP_LINK_TRAINING) { if (status != DC_FAIL_DP_LINK_TRAINING ||
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
BREAK_TO_DEBUGGER(); BREAK_TO_DEBUGGER();
return; return;
} }
......
...@@ -288,7 +288,7 @@ bool dc_stream_set_cursor_position( ...@@ -288,7 +288,7 @@ bool dc_stream_set_cursor_position(
pos_cpy.enable = false; pos_cpy.enable = false;
if (ipp !=NULL && ipp->funcs->ipp_cursor_set_position != NULL) if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL)
ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param); ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
if (mi != NULL && mi->funcs->set_cursor_position != NULL) if (mi != NULL && mi->funcs->set_cursor_position != NULL)
......
...@@ -348,29 +348,44 @@ static void set_audio_latency( ...@@ -348,29 +348,44 @@ static void set_audio_latency(
void dce_aud_az_enable(struct audio *audio) void dce_aud_az_enable(struct audio *audio)
{ {
struct dce_audio *aud = DCE_AUD(audio);
uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
if (get_reg_field_value(value, set_reg_field_value(value, 1,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
AUDIO_ENABLED) != 1) CLOCK_GATING_DISABLE);
set_reg_field_value(value, 1, set_reg_field_value(value, 1,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
AUDIO_ENABLED); AUDIO_ENABLED);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
dm_logger_write(CTX->logger, LOG_HW_AUDIO,
"\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n",
audio->inst, value);
} }
void dce_aud_az_disable(struct audio *audio) void dce_aud_az_disable(struct audio *audio)
{ {
uint32_t value; uint32_t value;
struct dce_audio *aud = DCE_AUD(audio);
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
set_reg_field_value(value, 0, set_reg_field_value(value, 0,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
AUDIO_ENABLED); AUDIO_ENABLED);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
set_reg_field_value(value, 0,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
CLOCK_GATING_DISABLE);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
dm_logger_write(CTX->logger, LOG_HW_AUDIO,
"\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n",
audio->inst, value);
} }
void dce_aud_az_configure( void dce_aud_az_configure(
...@@ -390,6 +405,11 @@ void dce_aud_az_configure( ...@@ -390,6 +405,11 @@ void dce_aud_az_configure(
bool is_ac3_supported = false; bool is_ac3_supported = false;
union audio_sample_rates sample_rate; union audio_sample_rates sample_rate;
uint32_t strlen = 0; uint32_t strlen = 0;
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
set_reg_field_value(value, 1,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
CLOCK_GATING_DISABLE);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
/* Speaker Allocation */ /* Speaker Allocation */
/* /*
...@@ -852,6 +872,7 @@ static bool dce_aud_endpoint_valid(struct audio *audio) ...@@ -852,6 +872,7 @@ static bool dce_aud_endpoint_valid(struct audio *audio)
void dce_aud_hw_init( void dce_aud_hw_init(
struct audio *audio) struct audio *audio)
{ {
uint32_t value;
struct dce_audio *aud = DCE_AUD(audio); struct dce_audio *aud = DCE_AUD(audio);
/* we only need to program the following registers once, so we only do /* we only need to program the following registers once, so we only do
...@@ -863,6 +884,12 @@ void dce_aud_hw_init( ...@@ -863,6 +884,12 @@ void dce_aud_hw_init(
* Suport R6 - 44.1khz * Suport R6 - 44.1khz
* Suport R7 - 48khz * Suport R7 - 48khz
*/ */
/*disable clock gating before write to endpoint register*/
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
set_reg_field_value(value, 1,
AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
CLOCK_GATING_DISABLE);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
REG_UPDATE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES, REG_UPDATE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
AUDIO_RATE_CAPABILITIES, 0x70); AUDIO_RATE_CAPABILITIES, 0x70);
......
...@@ -202,7 +202,7 @@ static void dcn10_log_hw_state(struct dc *dc) ...@@ -202,7 +202,7 @@ static void dcn10_log_hw_state(struct dc *dc)
DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t " DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t "
"h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n"); "h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n");
for (i = 0; i < pool->pipe_count; i++) { for (i = 0; i < pool->res_cap->num_timing_generator; i++) {
struct timing_generator *tg = pool->timing_generators[i]; struct timing_generator *tg = pool->timing_generators[i];
struct dcn_otg_state s = {0}; struct dcn_otg_state s = {0};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment