summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2019-02-25 13:26:34 -0500
committerAlex Deucher <alexander.deucher@amd.com>2019-06-22 09:34:07 -0500
commit97bda0322b8a91aa8d534763e709571b2334e585 (patch)
tree9e572c249b54a91c58a771d5eeef5ffc51cfe587
parentb4f199c7b00c87183f10c0a8f635f26ba2ede3eb (diff)
drm/amd/display: Add DSC support for Navi (v2)
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>
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile3
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c51
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c153
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c145
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dsc.h61
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h69
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c58
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/Makefile4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c688
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h573
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c93
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c38
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c184
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c168
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/Makefile13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c899
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c382
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c243
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h54
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h706
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c258
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h85
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c147
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_status.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h101
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h22
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c10
-rw-r--r--drivers/gpu/drm/amd/display/include/logger_types.h6
48 files changed, 5440 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index df951cbb4c6c..27afdb5db626 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -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
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index e6cd67342df8..7cf0573ab25f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -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)
{
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 9c0a755414de..00eaa69ba53d 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -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
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 052d3c8c6b73..68eddcc0fbcc 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -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
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index af22ff050e6f..1af06637fdda 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -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,
@@ -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;
}
@@ -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);
@@ -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);
@@ -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)
@@ -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)
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 4d0c2bb32dc5..effc36745671 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -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
@@ -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,
@@ -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: ");
@@ -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
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
index b0dea759cd86..8b22af9085e4 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -12,6 +12,12 @@
#include "dc_link_ddc.h"
#include "dm_helpers.h"
#include "dpcd_defs.h"
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#include "dsc.h"
+#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
+#include "resource.h"
+#endif
enum dc_status core_link_read_dpcd(
struct dc_link *link,
@@ -360,3 +366,142 @@ void dp_retrain_link_dp_test(struct dc_link *link,
}
}
}
+
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#define DC_LOGGER \
+ dsc->ctx->logger
+static void dsc_optc_config_log(struct display_stream_compressor *dsc,
+ struct dsc_optc_config *config)
+{
+ DC_LOG_DSC("Setting optc DSC config at DSC inst %d", dsc->inst);
+ DC_LOG_DSC("\n\tbytes_per_pixel %d\n\tis_pixel_format_444 %d\n\tslice_width %d",
+ config->bytes_per_pixel,
+ config->is_pixel_format_444, config->slice_width);
+}
+
+static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc *core_dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ bool result = false;
+
+ if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment))
+ result = true;
+ else
+ result = dm_helpers_dp_write_dsc_enable(core_dc->ctx, stream, enable);
+ return result;
+}
+
+/* This has to be done after DSC was enabled on RX first, i.e. after dp_enable_dsc_on_rx() had been called
+ */
+static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *core_dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+
+ if (enable) {
+ /* TODO proper function */
+ struct dsc_config dsc_cfg;
+ struct dsc_optc_config dsc_optc_cfg;
+ enum optc_dsc_mode optc_dsc_mode;
+ uint8_t dsc_packed_pps[128];
+
+ /* 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_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps[0]);
+ if (odm_pipe) {
+ struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc;
+ uint8_t dsc_packed_pps_odm[128];
+
+ dsc_cfg.pic_width /= 2;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= 2;
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
+ bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
+ bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst);
+ }
+ dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+
+ optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ /* Enable DSC in encoder */
+ if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width,
+ &dsc_packed_pps[0]);
+
+ /* Enable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+ } else {
+ /* disable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+ pipe_ctx->stream_res.tg,
+ OPTC_DSC_DISABLED, 0, 0);
+
+ /* disable DSC in stream encoder */
+ if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+ pipe_ctx->stream_res.stream_enc,
+ OPTC_DSC_DISABLED, 0, 0, NULL);
+ }
+
+ /* disable DSC block */
+ pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+ if (odm_pipe)
+ odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ }
+}
+
+bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ bool result = false;
+
+ if (!dsc)
+ goto out;
+
+ if (enable && stream->is_dsc_enabled) {
+ /* update dsc stream */
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ stream->is_dsc_enabled = true;
+ result = true;
+ } else if (enable && !stream->is_dsc_enabled) {
+ /* enable dsc on non dsc stream */
+ if (dp_set_dsc_on_rx(pipe_ctx, true)) {
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ stream->is_dsc_enabled = true;
+ result = true;
+ } else {
+ stream->is_dsc_enabled = false;
+ result = false;
+ }
+ } else if (!enable && stream->is_dsc_enabled) {
+ /* disable dsc on dsc stream */
+ dp_set_dsc_on_rx(pipe_ctx, false);
+ dp_set_dsc_on_stream(pipe_ctx, false);
+ stream->is_dsc_enabled = false;
+ result = true;
+ } else {
+ /* disable dsc on non dsc stream */
+ result = true;
+ }
+out:
+ return result;
+}
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index de50d778e4b0..3787398f6d80 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -105,6 +105,16 @@ static void construct(struct dc_stream_state *stream,
/* EDID CAP translation for HDMI 2.0 */
stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg));
+ stream->timing.dsc_cfg.num_slices_h = 0;
+ stream->timing.dsc_cfg.num_slices_v = 0;
+ stream->timing.dsc_cfg.bits_per_pixel = 128;
+ stream->timing.dsc_cfg.block_pred_enable = 1;
+ stream->timing.dsc_cfg.linebuf_depth = 9;
+ stream->timing.dsc_cfg.version_minor = 2;
+ stream->timing.dsc_cfg.ycbcr422_simple = 0;
+#endif
update_stream_signal(stream, dc_sink_data);
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 676f30e647b6..139ea7354910 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -331,6 +331,9 @@ struct dc_debug_options {
bool disable_dfs_bypass;
bool disable_dpp_power_gate;
bool disable_hubp_power_gate;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool disable_dsc_power_gate;
+#endif
bool disable_pplib_wm_range;
enum wm_report_mode pplib_wm_report_mode;
unsigned int min_disp_clk_khz;
@@ -363,6 +366,9 @@ struct dc_debug_options {
unsigned int force_fclk_khz;
bool disable_tri_buf;
struct dc_bw_validation_profile bw_val_profile;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool disable_fec;
+#endif
};
struct dc_debug_data {
@@ -894,6 +900,10 @@ struct dpcd_caps {
bool panel_mode_edp;
bool dpcd_display_control_capable;
bool ext_receiver_cap_field_present;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ union fec_capability fec_cap;
+ struct dsc_dec_dpcd_caps dsc_sink_caps;
+#endif
};
#include "dc_link.h"
@@ -928,6 +938,14 @@ struct dc_sink {
struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX];
bool converter_disable_audio;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ struct dc_sink_dsc_caps {
+ // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology),
+ // 'false' if they are sink's DSC caps
+ bool is_virtual_dpcd_dsc;
+ struct dsc_dec_dpcd_caps dsc_dec_caps;
+ } sink_dsc_caps;
+#endif
/* private to DC core */
struct dc_link *link;
@@ -986,4 +1004,10 @@ unsigned int dc_get_target_backlight_pwm(struct dc *dc);
bool dc_is_dmcu_initialized(struct dc *dc);
+#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
+/*******************************************************************************
+ * DSC Interfaces
+ ******************************************************************************/
+#include "dc_dsc.h"