Commit 688486a4 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'amd-drm-next-5.6-2020-01-10-dp-mst-dsc' of...

Merge tag 'amd-drm-next-5.6-2020-01-10-dp-mst-dsc' of git://people.freedesktop.org/~agd5f/linux into drm-next

amd-drm-next-5.6-2020-01-10-dp-mst-dsc:

drm:
- Add MST helper for PBN calculation of DSC modes
- Parse FEC caps on MST ports
- Add MST DPCD R/W functions
- Add MST helpers for virtual DPCD aux
- Add MST HUB quirk
- Add MST DSC enablement helpers

amdgpu:
- Enable MST DSC
- Add fair share algo for DSC bandwidth calcs
- Fix for 32 bit builds
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
From: Alex Deucher <alexdeucher@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200110214328.308549-1-alexander.deucher@amd.com
parents d5d88cd6 485b747e
...@@ -4933,12 +4933,13 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, ...@@ -4933,12 +4933,13 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
is_y420); is_y420);
bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
clock = adjusted_mode->clock; clock = adjusted_mode->clock;
dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp); dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false);
} }
dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state, dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state,
mst_mgr, mst_mgr,
mst_port, mst_port,
dm_new_connector_state->pbn); dm_new_connector_state->pbn,
0);
if (dm_new_connector_state->vcpi_slots < 0) { if (dm_new_connector_state->vcpi_slots < 0) {
DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
return dm_new_connector_state->vcpi_slots; return dm_new_connector_state->vcpi_slots;
...@@ -4951,6 +4952,71 @@ const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = { ...@@ -4951,6 +4952,71 @@ const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
.atomic_check = dm_encoder_helper_atomic_check .atomic_check = dm_encoder_helper_atomic_check
}; };
#if defined(CONFIG_DRM_AMD_DC_DCN)
static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
struct dc_state *dc_state)
{
struct dc_stream_state *stream = NULL;
struct drm_connector *connector;
struct drm_connector_state *new_con_state, *old_con_state;
struct amdgpu_dm_connector *aconnector;
struct dm_connector_state *dm_conn_state;
int i, j, clock, bpp;
int vcpi, pbn_div, pbn = 0;
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
aconnector = to_amdgpu_dm_connector(connector);
if (!aconnector->port)
continue;
if (!new_con_state || !new_con_state->crtc)
continue;
dm_conn_state = to_dm_connector_state(new_con_state);
for (j = 0; j < dc_state->stream_count; j++) {
stream = dc_state->streams[j];
if (!stream)
continue;
if ((struct amdgpu_dm_connector*)stream->dm_stream_context == aconnector)
break;
stream = NULL;
}
if (!stream)
continue;
if (stream->timing.flags.DSC != 1) {
drm_dp_mst_atomic_enable_dsc(state,
aconnector->port,
dm_conn_state->pbn,
0,
false);
continue;
}
pbn_div = dm_mst_get_pbn_divider(stream->link);
bpp = stream->timing.dsc_cfg.bits_per_pixel;
clock = stream->timing.pix_clk_100hz / 10;
pbn = drm_dp_calc_pbn_mode(clock, bpp, true);
vcpi = drm_dp_mst_atomic_enable_dsc(state,
aconnector->port,
pbn, pbn_div,
true);
if (vcpi < 0)
return vcpi;
dm_conn_state->pbn = pbn;
dm_conn_state->vcpi_slots = vcpi;
}
return 0;
}
#endif
static void dm_drm_plane_reset(struct drm_plane *plane) static void dm_drm_plane_reset(struct drm_plane *plane)
{ {
struct dm_plane_state *amdgpu_state = NULL; struct dm_plane_state *amdgpu_state = NULL;
...@@ -7829,6 +7895,29 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, ...@@ -7829,6 +7895,29 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm,
return ret; return ret;
} }
static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc)
{
struct drm_connector *connector;
struct drm_connector_state *conn_state;
struct amdgpu_dm_connector *aconnector = NULL;
int i;
for_each_new_connector_in_state(state, connector, conn_state, i) {
if (conn_state->crtc != crtc)
continue;
aconnector = to_amdgpu_dm_connector(connector);
if (!aconnector->port || !aconnector->mst_port)
aconnector = NULL;
else
break;
}
if (!aconnector)
return 0;
return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_port->mst_mgr);
}
/** /**
* amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM. * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
* @dev: The DRM device * @dev: The DRM device
...@@ -7881,6 +7970,16 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -7881,6 +7970,16 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (ret) if (ret)
goto fail; goto fail;
if (adev->asic_type >= CHIP_NAVI10) {
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = add_affected_mst_dsc_crtcs(state, crtc);
if (ret)
goto fail;
}
}
}
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
!new_crtc_state->color_mgmt_changed && !new_crtc_state->color_mgmt_changed &&
...@@ -7984,11 +8083,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -7984,11 +8083,6 @@ 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
...@@ -8057,6 +8151,15 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -8057,6 +8151,15 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (ret) if (ret)
goto fail; goto fail;
#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!compute_mst_dsc_configs_for_state(state, dm_state->context))
goto fail;
ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context);
if (ret)
goto fail;
#endif
if (dc_validate_global_state(dc, dm_state->context, false) != DC_OK) { if (dc_validate_global_state(dc, dm_state->context, false) != DC_OK) {
ret = -EINVAL; ret = -EINVAL;
goto fail; goto fail;
...@@ -8085,6 +8188,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -8085,6 +8188,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
dc_retain_state(old_dm_state->context); dc_retain_state(old_dm_state->context);
} }
} }
/* Perform validation of MST topology in the state*/
ret = drm_dp_mst_atomic_check(state);
if (ret)
goto fail;
/* Store the overall update type for use later in atomic check. */ /* Store the overall update type for use later in atomic check. */
for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) { for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
......
...@@ -330,6 +330,7 @@ struct amdgpu_dm_connector { ...@@ -330,6 +330,7 @@ struct amdgpu_dm_connector {
struct drm_dp_mst_port *port; struct drm_dp_mst_port *port;
struct amdgpu_dm_connector *mst_port; struct amdgpu_dm_connector *mst_port;
struct amdgpu_encoder *mst_encoder; struct amdgpu_encoder *mst_encoder;
struct drm_dp_aux *dsc_aux;
/* TODO see if we can merge with ddc_bus or make a dm_connector */ /* TODO see if we can merge with ddc_bus or make a dm_connector */
struct amdgpu_i2c_adapter *i2c; struct amdgpu_i2c_adapter *i2c;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "dc.h" #include "dc.h"
#include "amdgpu_dm.h" #include "amdgpu_dm.h"
#include "amdgpu_dm_irq.h" #include "amdgpu_dm_irq.h"
#include "amdgpu_dm_mst_types.h"
#include "dm_helpers.h" #include "dm_helpers.h"
...@@ -516,8 +517,24 @@ bool dm_helpers_dp_write_dsc_enable( ...@@ -516,8 +517,24 @@ bool dm_helpers_dp_write_dsc_enable(
) )
{ {
uint8_t enable_dsc = enable ? 1 : 0; uint8_t enable_dsc = enable ? 1 : 0;
struct amdgpu_dm_connector *aconnector;
if (!stream)
return false;
return dm_helpers_dp_write_dpcd(ctx, stream->sink->link, DP_DSC_ENABLE, &enable_dsc, 1); if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
if (!aconnector->dsc_aux)
return false;
return (drm_dp_dpcd_write(aconnector->dsc_aux, DP_DSC_ENABLE, &enable_dsc, 1) >= 0);
}
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT)
return dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
return false;
} }
bool dm_helpers_is_dp_sink_present(struct dc_link *link) bool dm_helpers_is_dp_sink_present(struct dc_link *link)
......
...@@ -29,7 +29,14 @@ ...@@ -29,7 +29,14 @@
struct amdgpu_display_manager; struct amdgpu_display_manager;
struct amdgpu_dm_connector; struct amdgpu_dm_connector;
int dm_mst_get_pbn_divider(struct dc_link *link);
void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconnector); struct amdgpu_dm_connector *aconnector);
#if defined(CONFIG_DRM_AMD_DC_DCN)
bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
struct dc_state *dc_state);
#endif
#endif #endif
...@@ -525,6 +525,9 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -525,6 +525,9 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable)
struct dsc_config dsc_cfg; struct dsc_config dsc_cfg;
uint8_t dsc_packed_pps[128]; uint8_t dsc_packed_pps[128];
memset(&dsc_cfg, 0, sizeof(dsc_cfg));
memset(dsc_packed_pps, 0, 128);
/* Enable DSC hw block */ /* Enable DSC hw block */
dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
......
...@@ -206,6 +206,9 @@ static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const str ...@@ -206,6 +206,9 @@ static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const str
struct dsc_reg_values dsc_reg_vals; struct dsc_reg_values dsc_reg_vals;
struct dsc_optc_config dsc_optc_cfg; struct dsc_optc_config dsc_optc_cfg;
memset(&dsc_reg_vals, 0, sizeof(dsc_reg_vals));
memset(&dsc_optc_cfg, 0, sizeof(dsc_optc_cfg));
DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); DC_LOG_DSC("Getting packed DSC PPS for DSC Config:");
dsc_config_log(dsc, dsc_cfg); dsc_config_log(dsc, dsc_cfg);
DC_LOG_DSC("DSC Picture Parameter Set (PPS):"); DC_LOG_DSC("DSC Picture Parameter Set (PPS):");
......
...@@ -1569,7 +1569,7 @@ static void release_dsc(struct resource_context *res_ctx, ...@@ -1569,7 +1569,7 @@ static void release_dsc(struct resource_context *res_ctx,
static enum dc_status add_dsc_to_stream_resource(struct dc *dc, enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc,
struct dc_state *dc_ctx, struct dc_state *dc_ctx,
struct dc_stream_state *dc_stream) struct dc_stream_state *dc_stream)
{ {
...@@ -1584,6 +1584,9 @@ static enum dc_status add_dsc_to_stream_resource(struct dc *dc, ...@@ -1584,6 +1584,9 @@ static enum dc_status add_dsc_to_stream_resource(struct dc *dc,
if (pipe_ctx->stream != dc_stream) if (pipe_ctx->stream != dc_stream)
continue; continue;
if (pipe_ctx->stream_res.dsc)
continue;
acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc, i); acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc, i);
/* The number of DSCs can be less than the number of pipes */ /* The number of DSCs can be less than the number of pipes */
...@@ -1632,7 +1635,7 @@ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, ...@@ -1632,7 +1635,7 @@ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx,
/* Get a DSC if required and available */ /* Get a DSC if required and available */
if (result == DC_OK && dc_stream->timing.flags.DSC) if (result == DC_OK && dc_stream->timing.flags.DSC)
result = add_dsc_to_stream_resource(dc, new_ctx, dc_stream); result = dcn20_add_dsc_to_stream_resource(dc, new_ctx, dc_stream);
if (result == DC_OK) if (result == DC_OK)
result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream); result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream);
......
...@@ -157,6 +157,7 @@ void dcn20_calculate_dlg_params( ...@@ -157,6 +157,7 @@ void dcn20_calculate_dlg_params(
enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream);
enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream);
enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream);
enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream);
enum dc_status dcn20_get_default_swizzle_mode(struct dc_plane_state *plane_state); enum dc_status dcn20_get_default_swizzle_mode(struct dc_plane_state *plane_state);
......
...@@ -163,10 +163,6 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -163,10 +163,6 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
break; break;
} }
if (aux_dev->aux->is_remote)
res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf,
todo);
else
res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
if (res <= 0) if (res <= 0)
...@@ -215,10 +211,6 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -215,10 +211,6 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
break; break;
} }
if (aux_dev->aux->is_remote)
res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf,
todo);
else
res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
if (res <= 0) if (res <= 0)
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
#include <drm/drm_vblank.h> #include <drm/drm_vblank.h>
#include <drm/drm_dp_mst_helper.h>
#include "drm_crtc_helper_internal.h" #include "drm_crtc_helper_internal.h"
...@@ -266,7 +267,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, ...@@ -266,7 +267,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
/** /**
* drm_dp_dpcd_read() - read a series of bytes from the DPCD * drm_dp_dpcd_read() - read a series of bytes from the DPCD
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel (SST or MST)
* @offset: address of the (first) register to read * @offset: address of the (first) register to read
* @buffer: buffer to store the register values * @buffer: buffer to store the register values
* @size: number of bytes in @buffer * @size: number of bytes in @buffer
...@@ -295,13 +296,18 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, ...@@ -295,13 +296,18 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
* We just have to do it before any DPCD access and hope that the * We just have to do it before any DPCD access and hope that the
* monitor doesn't power down exactly after the throw away read. * monitor doesn't power down exactly after the throw away read.
*/ */
ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, buffer, if (!aux->is_remote) {
1); ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV,
buffer, 1);
if (ret != 1) if (ret != 1)
goto out; goto out;
}
ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, if (aux->is_remote)
size); ret = drm_dp_mst_dpcd_read(aux, offset, buffer, size);
else
ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset,
buffer, size);
out: out:
drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret); drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret);
...@@ -311,7 +317,7 @@ EXPORT_SYMBOL(drm_dp_dpcd_read); ...@@ -311,7 +317,7 @@ EXPORT_SYMBOL(drm_dp_dpcd_read);
/** /**
* drm_dp_dpcd_write() - write a series of bytes to the DPCD * drm_dp_dpcd_write() - write a series of bytes to the DPCD
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel (SST or MST)
* @offset: address of the (first) register to write * @offset: address of the (first) register to write
* @buffer: buffer containing the values to write * @buffer: buffer containing the values to write
* @size: number of bytes in @buffer * @size: number of bytes in @buffer
...@@ -328,8 +334,12 @@ ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, ...@@ -328,8 +334,12 @@ ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
{ {
int ret; int ret;
ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, if (aux->is_remote)
size); ret = drm_dp_mst_dpcd_write(aux, offset, buffer, size);
else
ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset,
buffer, size);
drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret); drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret);
return ret; return ret;
} }
...@@ -968,6 +978,19 @@ static void drm_dp_aux_crc_work(struct work_struct *work) ...@@ -968,6 +978,19 @@ static void drm_dp_aux_crc_work(struct work_struct *work)
} }
} }
/**
* drm_dp_remote_aux_init() - minimally initialise a remote aux channel
* @aux: DisplayPort AUX channel
*
* Used for remote aux channel in general. Merely initialize the crc work
* struct.
*/
void drm_dp_remote_aux_init(struct drm_dp_aux *aux)
{
INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work);
}
EXPORT_SYMBOL(drm_dp_remote_aux_init);
/** /**
* drm_dp_aux_init() - minimally initialise an aux channel * drm_dp_aux_init() - minimally initialise an aux channel
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
...@@ -1155,6 +1178,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { ...@@ -1155,6 +1178,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = {
{ OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) }, { OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) },
/* CH7511 seems to leave SINK_COUNT zeroed */ /* CH7511 seems to leave SINK_COUNT zeroed */
{ OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) }, { OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) },
/* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */
{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) },
}; };
#undef OUI #undef OUI
......
This diff is collapsed.
...@@ -61,10 +61,11 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, ...@@ -61,10 +61,11 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
crtc_state->pipe_bpp = bpp; crtc_state->pipe_bpp = bpp;
crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock,
crtc_state->pipe_bpp); crtc_state->pipe_bpp,
false);
slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
port, crtc_state->pbn); port, crtc_state->pbn, 0);
if (slots == -EDEADLK) if (slots == -EDEADLK)
return slots; return slots;
if (slots >= 0) if (slots >= 0)
......
...@@ -806,11 +806,11 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, ...@@ -806,11 +806,11 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
* topology * topology
*/ */
asyh->or.bpc = min(connector->display_info.bpc, 8U); asyh->or.bpc = min(connector->display_info.bpc, 8U);
asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3); asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3, false);
} }
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port, slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port,
asyh->dp.pbn); asyh->dp.pbn, 0);
if (slots < 0) if (slots < 0)
return slots; return slots;
......
...@@ -518,7 +518,7 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder, ...@@ -518,7 +518,7 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
mst_enc = radeon_encoder->enc_priv; mst_enc = radeon_encoder->enc_priv;
mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp); mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp, false);
mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices; mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n", DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
......
...@@ -18,15 +18,19 @@ int igt_dp_mst_calc_pbn_mode(void *ignored) ...@@ -18,15 +18,19 @@ int igt_dp_mst_calc_pbn_mode(void *ignored)
int rate; int rate;
int bpp; int bpp;
int expected; int expected;
bool dsc;
} test_params[] = { } test_params[] = {
{ 154000, 30, 689 }, { 154000, 30, 689, false },
{ 234000, 30, 1047 }, { 234000, 30, 1047, false },
{ 297000, 24, 1063 }, { 297000, 24, 1063, false },
{ 332880, 24, 50, true },
{ 324540, 24, 49, true },
}; };
for (i = 0; i < ARRAY_SIZE(test_params); i++) { for (i = 0; i < ARRAY_SIZE(test_params); i++) {
pbn = drm_dp_calc_pbn_mode(test_params[i].rate, pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
test_params[i].bpp); test_params[i].bpp,
test_params[i].dsc);
FAIL(pbn != test_params[i].expected, FAIL(pbn != test_params[i].expected,
"Expected PBN %d for clock %d bpp %d, got %d\n", "Expected PBN %d for clock %d bpp %d, got %d\n",
test_params[i].expected, test_params[i].rate, test_params[i].expected, test_params[i].rate,
......
...@@ -1465,6 +1465,7 @@ int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); ...@@ -1465,6 +1465,7 @@ int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4], struct drm_dp_aux *aux); const u8 port_cap[4], struct drm_dp_aux *aux);
void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
void drm_dp_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux);
int drm_dp_aux_register(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux);
void drm_dp_aux_unregister(struct drm_dp_aux *aux); void drm_dp_aux_unregister(struct drm_dp_aux *aux);
...@@ -1522,6 +1523,13 @@ enum drm_dp_quirk { ...@@ -1522,6 +1523,13 @@ enum drm_dp_quirk {
* The driver should ignore SINK_COUNT during detection. * The driver should ignore SINK_COUNT during detection.
*/ */
DP_DPCD_QUIRK_NO_SINK_COUNT, DP_DPCD_QUIRK_NO_SINK_COUNT,
/**
* @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD:
*
* The device supports MST DSC despite not supporting Virtual DPCD.
* The DSC caps can be read from the physical aux instead.
*/
DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD,
}; };
/** /**
......
...@@ -156,6 +156,8 @@ struct drm_dp_mst_port { ...@@ -156,6 +156,8 @@ struct drm_dp_mst_port {
* audio-capable. * audio-capable.
*/ */
bool has_audio; bool has_audio;
bool fec_capable;
}; };
/** /**
...@@ -383,6 +385,7 @@ struct drm_dp_port_number_req { ...@@ -383,6 +385,7 @@ struct drm_dp_port_number_req {
struct drm_dp_enum_path_resources_ack_reply { struct drm_dp_enum_path_resources_ack_reply {
u8 port_number; u8 port_number;
bool fec_capable;
u16 full_payload_bw_number; u16 full_payload_bw_number;
u16 avail_payload_bw_number; u16 avail_payload_bw_number;
}; };
...@@ -499,6 +502,8 @@ struct drm_dp_payload { ...@@ -499,6 +502,8 @@ struct drm_dp_payload {
struct drm_dp_vcpi_allocation { struct drm_dp_vcpi_allocation {
struct drm_dp_mst_port *port; struct drm_dp_mst_port *port;
int vcpi; int vcpi;
int pbn;
bool dsc_enabled;
struct list_head next; struct list_head next;
}; };
...@@ -727,8 +732,7 @@ bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, ...@@ -727,8 +732,7 @@ bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
int drm_dp_calc_pbn_mode(int clock, int bpp); int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc);
bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, int pbn, int slots); struct drm_dp_mst_port *port, int pbn, int slots);
...@@ -777,7 +781,15 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a ...@@ -777,7 +781,15 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a
int __must_check int __must_check
drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, int pbn); struct drm_dp_mst_port *port, int pbn,
int pbn_div);
int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state,
struct drm_dp_mst_port *port,
int pbn, int pbn_div,
bool enable);
int __must_check
drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr);
int __must_check int __must_check
drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_mgr *mgr,
...@@ -789,6 +801,8 @@ int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); ...@@ -789,6 +801,8 @@ int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state);
void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port);
void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port);
struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port);
extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs;
/** /**
......
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