Skip to content

Commit

Permalink
drm/amd/display: Add DSC support for Navi (v2)
Browse files Browse the repository at this point in the history
Add support for DCN2 DSC (Display Stream Compression)

HW Blocks:

 +--------++------+       +----------+
 | HUBBUB || HUBP |  <--  | MMHUBBUB |
 +--------++------+       +----------+
        |                     ^
        v                     |
    +--------+            +--------+
    |  DPP   |            |  DWB   |
    +--------+            +--------+
        |
        v                      ^
    +--------+                 |
    |  MPC   |                 |
    +--------+                 |
        |                      |
        v                      |
    +-------+      +-------+   |
    |  OPP  | <--> |  DSC  |   |
    +-------+      +-------+   |
        |                      |
        v                      |
    +--------+                /
    |  OPTC  |  --------------
    +--------+
        |
        v
    +--------+       +--------+
    |  DIO   |       |  DCCG  |
    +--------+       +--------+

v2: rebase (Alex)

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Harry Wentland authored and Alex Deucher committed Jun 22, 2019
1 parent b4f199c commit 97bda03
Show file tree
Hide file tree
Showing 48 changed files with 5,440 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/gpu/drm/amd/display/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ config DRM_AMD_DC_DCN2_0
Choose this option if you want to have
Navi support for display engine

config DRM_AMD_DC_DSC_SUPPORT
bool "DSC support"
default n
depends on DRM_AMD_DC && X86
depends on DRM_AMD_DC_DCN1_0
depends on DRM_AMD_DC_DCN2_0
help
Choose this option if you want to have
Dynamic Stream Compression support

config DEBUG_KERNEL_DC
bool "Enable kgdb break in DC"
depends on DRM_AMD_DC
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,16 @@ bool dm_helpers_submit_i2c(

return result;
}
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
bool dm_helpers_dp_write_dsc_enable(
struct dc_context *ctx,
const struct dc_stream_state *stream,
bool enable
)
{
return false;
}
#endif

bool dm_helpers_is_dp_sink_present(struct dc_link *link)
{
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/amd/display/dc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ DC_LIBS += dcn20
endif


ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
DC_LIBS += dsc
endif

ifdef CONFIG_DRM_AMD_DC_DCN1_0
DC_LIBS += dcn10 dml
Expand Down
21 changes: 21 additions & 0 deletions drivers/gpu/drm/amd/display/dc/core/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@

#include "dc_link_dp.h"

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
#include "dsc.h"
#endif

#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#include "vm_helper.h"
#endif
Expand Down Expand Up @@ -1730,6 +1734,23 @@ static void commit_planes_do_stream_update(struct dc *dc,
#endif
}

#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
if (stream_update->dsc_config && dc->hwss.pipe_control_lock_global) {
if (stream_update->dsc_config->num_slices_h &&
stream_update->dsc_config->num_slices_v) {
/* dsc enable */
dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true);
dp_set_dsc_enable(pipe_ctx, true);
dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false);
} else {
/* dsc disable */
dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true);
dp_set_dsc_enable(pipe_ctx, false);
dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false);
}

}
#endif
/* Full fe update*/
if (update_type == UPDATE_TYPE_FAST)
continue;
Expand Down
51 changes: 51 additions & 0 deletions drivers/gpu/drm/amd/display/dc/core/dc_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,9 @@ static enum dc_status enable_link_dp(
if (link_settings.link_rate == LINK_RATE_LOW)
skip_video_pattern = false;

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
dp_set_fec_ready(link, true);
#endif

if (perform_link_training_with_retries(
link,
Expand All @@ -1520,6 +1523,9 @@ static enum dc_status enable_link_dp(
else
status = DC_FAIL_DP_LINK_TRAINING;

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
dp_set_fec_enable(link, true);
#endif
return status;
}

Expand Down Expand Up @@ -2142,6 +2148,14 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
dp_disable_link_phy(link, signal);
else
dp_disable_link_phy_mst(link, signal);
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT

if (dc_is_dp_sst_signal(signal) ||
link->mst_stream_alloc_table.stream_count == 0) {
dp_set_fec_enable(link, false);
dp_set_fec_ready(link, false);
}
#endif
} else
link->link_enc->funcs->disable_output(link->link_enc, signal);

Expand Down Expand Up @@ -2376,6 +2390,11 @@ static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream)
&stream->link->cur_link_settings);
link_rate_in_mbytes_per_sec /= 8000; /* Kbits to MBytes */

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (stream->link->fec_state != dc_link_fec_not_ready)
link_rate_in_mbytes_per_sec = (link_rate_in_mbytes_per_sec * 970)/1000;
#endif

mbytes_per_sec = dc_fixpt_from_int(link_rate_in_mbytes_per_sec);

return dc_fixpt_div_int(mbytes_per_sec, 54);
Expand Down Expand Up @@ -2738,12 +2757,30 @@ void core_link_enable_stream(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
allocate_mst_payload(pipe_ctx);

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (pipe_ctx->stream->timing.flags.DSC &&
(dc_is_dp_signal(pipe_ctx->stream->signal) ||
dc_is_virtual_signal(pipe_ctx->stream->signal))) {
dp_set_dsc_enable(pipe_ctx, true);
pipe_ctx->stream_res.tg->funcs->wait_for_state(
pipe_ctx->stream_res.tg,
CRTC_STATE_VBLANK);
}
#endif
core_dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->link->cur_link_settings);

if (dc_is_dp_signal(pipe_ctx->stream->signal))
enable_stream_features(pipe_ctx);
}
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
else { // if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment))
if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
dc_is_virtual_signal(pipe_ctx->stream->signal))
dp_set_dsc_enable(pipe_ctx, true);

}
#endif
}

void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
Expand Down Expand Up @@ -2784,6 +2821,12 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
core_dc->hwss.disable_stream(pipe_ctx, option);

disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (pipe_ctx->stream->timing.flags.DSC &&
dc_is_dp_signal(pipe_ctx->stream->signal)) {
dp_set_dsc_enable(pipe_ctx, false);
}
#endif
}

void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
Expand Down Expand Up @@ -2851,6 +2894,14 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
uint32_t bits_per_channel = 0;
uint32_t kbps;

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (timing->flags.DSC) {
kbps = (timing->pix_clk_100hz * timing->dsc_cfg.bits_per_pixel);
kbps = kbps / 160 + ((kbps % 160) ? 1 : 0);
return kbps;
}
#endif

switch (timing->display_color_depth) {
case COLOR_DEPTH_666:
bits_per_channel = 6;
Expand Down
153 changes: 153 additions & 0 deletions drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "dc_link_dp.h"
#include "dm_helpers.h"
#include "opp.h"
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
#include "dsc.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#include "resource.h"
#endif
Expand Down Expand Up @@ -2379,6 +2382,10 @@ static bool retrieve_link_cap(struct dc_link *link)
uint32_t read_dpcd_retry_cnt = 3;
int i;
struct dp_sink_hw_fw_revision dp_hw_fw_revision;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
uint8_t dsc_data[16];
struct dsc_dec_dpcd_caps *dsc_caps;
#endif

memset(dpcd_data, '\0', sizeof(dpcd_data));
memset(&down_strm_port_count,
Expand Down Expand Up @@ -2550,6 +2557,90 @@ static bool retrieve_link_cap(struct dc_link *link)
dp_hw_fw_revision.ieee_fw_rev,
sizeof(dp_hw_fw_revision.ieee_fw_rev));

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
dsc_caps = &link->dpcd_caps.dsc_sink_caps;
memset(dsc_caps, '\0', sizeof(*dsc_caps));
memset(&link->dpcd_caps.dsc_sink_caps, '\0',
sizeof(link->dpcd_caps.dsc_sink_caps));
memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
/* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
status = core_link_read_dpcd(
link,
DP_DSC_SUPPORT,
dsc_data,
sizeof(dsc_data));
if (status == DC_OK) {
DC_LOG_DSC("DSC capability read at link %d:",
link->link_index);
DC_LOG_DSC("\t%02x %02x %02x %02x",
dsc_data[0], dsc_data[1],
dsc_data[2], dsc_data[3]);
DC_LOG_DSC("\t%02x %02x %02x %02x",
dsc_data[4], dsc_data[5],
dsc_data[6], dsc_data[7]);
DC_LOG_DSC("\t%02x %02x %02x %02x",
dsc_data[8], dsc_data[9],
dsc_data[10], dsc_data[11]);
DC_LOG_DSC("\t%02x %02x %02x %02x",
dsc_data[12], dsc_data[13],
dsc_data[14], dsc_data[15]);
} else {
dm_error("%s: Read DSC dpcd data failed.\n", __func__);
return false;
}

if (dc_dsc_parse_dsc_dpcd(dsc_data,
dsc_caps)) {
DC_LOG_DSC("DSC capability parsed at link %d:",
link->link_index);
DC_LOG_DSC("\tis_dsc_supported:\t%d",
dsc_caps->is_dsc_supported);
DC_LOG_DSC("\tdsc_version:\t%d", dsc_caps->dsc_version);
DC_LOG_DSC("\trc_buffer_size:\t%d",
dsc_caps->rc_buffer_size);
DC_LOG_DSC("\tslice_caps1:\t0x%x20",
dsc_caps->slice_caps1.raw);
DC_LOG_DSC("\tslice_caps2:\t0x%x20",
dsc_caps->slice_caps2.raw);
DC_LOG_DSC("\tlb_bit_depth:\t%d",
dsc_caps->lb_bit_depth);
DC_LOG_DSC("\tis_block_pred_supported:\t%d",
dsc_caps->is_block_pred_supported);
DC_LOG_DSC("\tedp_max_bits_per_pixel:\t%d",
dsc_caps->edp_max_bits_per_pixel);
DC_LOG_DSC("\tcolor_formats:\t%d",
dsc_caps->color_formats.raw);
DC_LOG_DSC("\tcolor_depth:\t%d",
dsc_caps->color_depth.raw);
DC_LOG_DSC("\tthroughput_mode_0_mps:\t%d",
dsc_caps->throughput_mode_0_mps);
DC_LOG_DSC("\tthroughput_mode_1_mps:\t%d",
dsc_caps->throughput_mode_1_mps);
DC_LOG_DSC("\tmax_slice_width:\t%d",
dsc_caps->max_slice_width);
DC_LOG_DSC("\tbpp_increment_div:\t%d",
dsc_caps->bpp_increment_div);
} else {
/* Some sinks return bogus DSC DPCD data
* when they don't support DSC.
*/
dm_error("%s: DSC DPCD data doesn't make sense. "
"DSC will be disabled.\n", __func__);
memset(&link->dpcd_caps.dsc_sink_caps, '\0',
sizeof(link->dpcd_caps.dsc_sink_caps));
}

status = core_link_read_dpcd(
link,
DP_FEC_CAPABILITY,
&link->dpcd_caps.fec_cap.raw,
sizeof(link->dpcd_caps.fec_cap.raw));
if (status != DC_OK)
dm_error("%s: Read FEC dpcd register failed.\n",
__func__);
}
#endif

/* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
Expand Down Expand Up @@ -2964,4 +3055,66 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
}

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
void dp_set_fec_ready(struct dc_link *link, bool ready)
{
/* FEC has to be "set ready" before the link training.
* The policy is to always train with FEC
* if the sink supports it and leave it enabled on link.
* If FEC is not supported, disable it.
*/
struct link_encoder *link_enc = link->link_enc;
uint8_t fec_config = 0;

if (link->dc->debug.disable_fec ||
IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment))
return;

if (link_enc->funcs->fec_set_ready &&
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
if (link->fec_state == dc_link_fec_not_ready && ready) {
fec_config = 1;
if (core_link_write_dpcd(link,
DP_FEC_CONFIGURATION,
&fec_config,
sizeof(fec_config)) == DC_OK) {
link_enc->funcs->fec_set_ready(link_enc, true);
link->fec_state = dc_link_fec_ready;
} else {
dm_error("dpcd write failed to set fec_ready");
}
} else if (link->fec_state == dc_link_fec_ready && !ready) {
fec_config = 0;
core_link_write_dpcd(link,
DP_FEC_CONFIGURATION,
&fec_config,
sizeof(fec_config));
link->link_enc->funcs->fec_set_ready(
link->link_enc, false);
link->fec_state = dc_link_fec_not_ready;
}
}
}

void dp_set_fec_enable(struct dc_link *link, bool enable)
{
struct link_encoder *link_enc = link->link_enc;

if (link->dc->debug.disable_fec ||
IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment))
return;

if (link_enc->funcs->fec_set_enable &&
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
if (link->fec_state == dc_link_fec_ready && enable) {
msleep(1);
link_enc->funcs->fec_set_enable(link_enc, true);
link->fec_state = dc_link_fec_enabled;
} else if (link->fec_state == dc_link_fec_enabled && !enable) {
link_enc->funcs->fec_set_enable(link_enc, false);
link->fec_state = dc_link_fec_ready;
}
}
}
#endif

Loading

0 comments on commit 97bda03

Please sign in to comment.