drm/amd/display: Add MST atomic routines

- Adding encoder atomic check to find vcpi slots for a connector
- Using DRM helper functions to calculate PBN
- Adding connector atomic check to release vcpi slots if connector
loses CRTC
- Calculate  PBN and VCPI slots only once during atomic
check and store them on crtc_state to eliminate
redundant calculation
- Call drm_dp_mst_atomic_check to verify validity of MST topology
during state atomic check

v2: squashed previous 3 separate patches, removed DSC PBN calculation,
and added PBN and VCPI slots properties to amdgpu connector

v3:
- moved vcpi_slots and pbn properties to dm_crtc_state and dc_stream_state
- updates stream's vcpi_slots and pbn on commit
- separated patch from the DSC MST series

v4:
- set vcpi_slots and pbn properties to dm_connector_state
- copy porperties from connector state on to crtc state

v5:
- keep the pbn and vcpi values only on connnector state
- added a void pointer to the stream state instead on two ints,
because dc_stream_state is OS agnostic. Pointer points to the
current dm_connector_state.

v6:
- Remove new param from stream

v7:
- Fix error with using max capable bpc

v8:
- squash in fix from Gustavo A. R. Silva

Reviewed-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Mikita Lipski 2019-11-06 14:23:55 -05:00 committed by Alex Deucher
parent 622b2a0ab6
commit 3261e013c0
4 changed files with 108 additions and 41 deletions

View File

@ -4095,7 +4095,8 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
state->underscan_hborder = 0; state->underscan_hborder = 0;
state->underscan_vborder = 0; state->underscan_vborder = 0;
state->base.max_requested_bpc = 8; state->base.max_requested_bpc = 8;
state->vcpi_slots = 0;
state->pbn = 0;
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
state->abm_level = amdgpu_dm_abm_level; state->abm_level = amdgpu_dm_abm_level;
@ -4123,7 +4124,8 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
new_state->underscan_enable = state->underscan_enable; new_state->underscan_enable = state->underscan_enable;
new_state->underscan_hborder = state->underscan_hborder; new_state->underscan_hborder = state->underscan_hborder;
new_state->underscan_vborder = state->underscan_vborder; new_state->underscan_vborder = state->underscan_vborder;
new_state->vcpi_slots = state->vcpi_slots;
new_state->pbn = state->pbn;
return &new_state->base; return &new_state->base;
} }
@ -4520,10 +4522,64 @@ static void dm_encoder_helper_disable(struct drm_encoder *encoder)
} }
static int convert_dc_color_depth_into_bpc (enum dc_color_depth display_color_depth)
{
switch (display_color_depth) {
case COLOR_DEPTH_666:
return 6;
case COLOR_DEPTH_888:
return 8;
case COLOR_DEPTH_101010:
return 10;
case COLOR_DEPTH_121212:
return 12;
case COLOR_DEPTH_141414:
return 14;
case COLOR_DEPTH_161616:
return 16;
default:
break;
}
return 0;
}
static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
{ {
struct drm_atomic_state *state = crtc_state->state;
struct drm_connector *connector = conn_state->connector;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state);
const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
struct drm_dp_mst_topology_mgr *mst_mgr;
struct drm_dp_mst_port *mst_port;
enum dc_color_depth color_depth;
int clock, bpp = 0;
if (!aconnector->port || !aconnector->dc_sink)
return 0;
mst_port = aconnector->port;
mst_mgr = &aconnector->mst_port->mst_mgr;
if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
return 0;
if (!state->duplicated) {
color_depth = convert_color_depth_from_display_info(connector, conn_state);
bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
clock = adjusted_mode->clock;
dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp);
}
dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state,
mst_mgr,
mst_port,
dm_new_connector_state->pbn);
if (dm_new_connector_state->vcpi_slots < 0) {
DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
return dm_new_connector_state->vcpi_slots;
}
return 0; return 0;
} }
@ -7566,6 +7622,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (ret) if (ret)
goto fail; goto fail;
/* Perform validation of MST topology in the state*/
ret = drm_dp_mst_atomic_check(state);
if (ret)
goto fail;
if (state->legacy_cursor_update) { if (state->legacy_cursor_update) {
/* /*
* This is a fast cursor update coming from the plane update * This is a fast cursor update coming from the plane update

View File

@ -359,6 +359,8 @@ struct dm_connector_state {
bool underscan_enable; bool underscan_enable;
bool freesync_capable; bool freesync_capable;
uint8_t abm_level; uint8_t abm_level;
int vcpi_slots;
uint64_t pbn;
}; };
#define to_dm_connector_state(x)\ #define to_dm_connector_state(x)\

View File

@ -182,15 +182,19 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
bool enable) bool enable)
{ {
struct amdgpu_dm_connector *aconnector; struct amdgpu_dm_connector *aconnector;
struct dm_connector_state *dm_conn_state;
struct drm_dp_mst_topology_mgr *mst_mgr; struct drm_dp_mst_topology_mgr *mst_mgr;
struct drm_dp_mst_port *mst_port; struct drm_dp_mst_port *mst_port;
int slots = 0;
bool ret; bool ret;
int clock;
int bpp = 0;
int pbn = 0;
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
/* Accessing the connector state is required for vcpi_slots allocation
* and directly relies on behaviour in commit check
* that blocks before commit guaranteeing that the state
* is not gonna be swapped while still in use in commit tail */
dm_conn_state = to_dm_connector_state(aconnector->base.state);
if (!aconnector || !aconnector->mst_port) if (!aconnector || !aconnector->mst_port)
return false; return false;
@ -203,42 +207,10 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
mst_port = aconnector->port; mst_port = aconnector->port;
if (enable) { if (enable) {
clock = stream->timing.pix_clk_100hz / 10;
switch (stream->timing.display_color_depth) {
case COLOR_DEPTH_666:
bpp = 6;
break;
case COLOR_DEPTH_888:
bpp = 8;
break;
case COLOR_DEPTH_101010:
bpp = 10;
break;
case COLOR_DEPTH_121212:
bpp = 12;
break;
case COLOR_DEPTH_141414:
bpp = 14;
break;
case COLOR_DEPTH_161616:
bpp = 16;
break;
default:
ASSERT(bpp != 0);
break;
}
bpp = bpp * 3;
/* TODO need to know link rate */
pbn = drm_dp_calc_pbn_mode(clock, bpp);
slots = drm_dp_find_vcpi_slots(mst_mgr, pbn);
ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, slots);
ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port,
dm_conn_state->pbn,
dm_conn_state->vcpi_slots);
if (!ret) if (!ret)
return false; return false;

View File

@ -246,11 +246,43 @@ dm_dp_mst_detect(struct drm_connector *connector,
aconnector->port); aconnector->port);
} }
static int dm_dp_mst_atomic_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct drm_connector_state *new_conn_state =
drm_atomic_get_new_connector_state(state, connector);
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, connector);
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct drm_crtc_state *new_crtc_state;
struct drm_dp_mst_topology_mgr *mst_mgr;
struct drm_dp_mst_port *mst_port;
mst_port = aconnector->port;
mst_mgr = &aconnector->mst_port->mst_mgr;
if (!old_conn_state->crtc)
return 0;
if (new_conn_state->crtc) {
new_crtc_state = drm_atomic_get_old_crtc_state(state, new_conn_state->crtc);
if (!new_crtc_state ||
!drm_atomic_crtc_needs_modeset(new_crtc_state) ||
new_crtc_state->enable)
return 0;
}
return drm_dp_atomic_release_vcpi_slots(state,
mst_mgr,
mst_port);
}
static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = { static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = {
.get_modes = dm_dp_mst_get_modes, .get_modes = dm_dp_mst_get_modes,
.mode_valid = amdgpu_dm_connector_mode_valid, .mode_valid = amdgpu_dm_connector_mode_valid,
.atomic_best_encoder = dm_mst_atomic_best_encoder, .atomic_best_encoder = dm_mst_atomic_best_encoder,
.detect_ctx = dm_dp_mst_detect, .detect_ctx = dm_dp_mst_detect,
.atomic_check = dm_dp_mst_atomic_check,
}; };
static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)