aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch6344
1 files changed, 6344 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch
new file mode 100644
index 00000000..8d49dd96
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch
@@ -0,0 +1,6344 @@
+From 3189f14a11f4013cccbb9b41bef382104b8afc4f Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Mon, 25 Feb 2019 13:26:34 -0500
+Subject: [PATCH 2456/2940] 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>
+---
+ drivers/gpu/drm/amd/display/Kconfig | 10 +
+ .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 10 +
+ drivers/gpu/drm/amd/display/dc/Makefile | 3 +
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 21 +
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 51 +
+ .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 153 +++
+ .../drm/amd/display/dc/core/dc_link_hwss.c | 145 +++
+ .../gpu/drm/amd/display/dc/core/dc_stream.c | 10 +
+ drivers/gpu/drm/amd/display/dc/dc.h | 24 +
+ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 14 +
+ drivers/gpu/drm/amd/display/dc/dc_dsc.h | 61 ++
+ drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 18 +
+ drivers/gpu/drm/amd/display/dc/dc_link.h | 10 +
+ drivers/gpu/drm/amd/display/dc/dc_stream.h | 6 +
+ drivers/gpu/drm/amd/display/dc/dc_types.h | 69 ++
+ .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 58 ++
+ .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 18 +
+ drivers/gpu/drm/amd/display/dc/dcn20/Makefile | 4 +
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c | 688 ++++++++++++++
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h | 573 +++++++++++
+ .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 93 ++
+ .../amd/display/dc/dcn20/dcn20_link_encoder.c | 20 +
+ .../amd/display/dc/dcn20/dcn20_link_encoder.h | 3 +
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_optc.c | 38 +
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_optc.h | 6 +
+ .../drm/amd/display/dc/dcn20/dcn20_resource.c | 184 ++++
+ .../display/dc/dcn20/dcn20_stream_encoder.c | 168 ++++
+ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 7 +
+ drivers/gpu/drm/amd/display/dc/dsc/Makefile | 13 +
+ drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c | 899 ++++++++++++++++++
+ .../gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c | 382 ++++++++
+ .../gpu/drm/amd/display/dc/dsc/dsc_helpers.c | 243 +++++
+ .../gpu/drm/amd/display/dc/dsc/dscc_types.h | 54 ++
+ .../gpu/drm/amd/display/dc/dsc/qp_tables.h | 706 ++++++++++++++
+ drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c | 258 +++++
+ drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h | 85 ++
+ .../gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c | 147 +++
+ .../gpu/drm/amd/display/dc/inc/core_status.h | 5 +
+ .../gpu/drm/amd/display/dc/inc/core_types.h | 9 +
+ .../gpu/drm/amd/display/dc/inc/dc_link_dp.h | 6 +
+ drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h | 101 ++
+ .../gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 7 +
+ .../drm/amd/display/dc/inc/hw/link_encoder.h | 13 +
+ .../amd/display/dc/inc/hw/stream_encoder.h | 22 +
+ .../amd/display/dc/inc/hw/timing_generator.h | 6 +
+ drivers/gpu/drm/amd/display/dc/inc/resource.h | 3 +
+ .../dc/virtual/virtual_stream_encoder.c | 10 +
+ .../drm/amd/display/include/logger_types.h | 6 +
+ 48 files changed, 5440 insertions(+)
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dc_dsc.h
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/Makefile
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
+
+diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
+index a2eba0d6a55f..9cb2211edf4c 100644
+--- a/drivers/gpu/drm/amd/display/Kconfig
++++ b/drivers/gpu/drm/amd/display/Kconfig
+@@ -24,6 +24,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 b4969e400ff8..9f8597280814 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 7f0eb44b5d67..5b26c76b906b 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -58,6 +58,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
+@@ -1742,6 +1746,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 ff1c3abb7a51..b43bcdfd0caf 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 44ecf1ca613a..0a0d6e4f03d5 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -334,6 +334,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;
+@@ -366,6 +369,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 {
+@@ -908,6 +914,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"
+@@ -942,6 +952,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;
+@@ -1000,4 +1018,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"
++#endif
+ #endif /* DC_INTERFACE_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+index 11c68a399267..6892bf80c9e0 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+@@ -512,4 +512,18 @@ union test_misc {
+ unsigned char raw;
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* FEC capability DPCD register field bits-*/
++union fec_capability {
++ struct {
++ uint8_t FEC_CAPABLE:1;
++ uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
++ uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
++ uint8_t BIT_ERROR_COUNT_CAPABLE:1;
++ uint8_t RESERVED:4;
++ } bits;
++ uint8_t raw;
++};
++#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */
++
+ #endif /* DC_DP_TYPES_H */
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h
+new file mode 100644
+index 000000000000..c3a277c11489
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h
+@@ -0,0 +1,61 @@
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#ifndef DC_DSC_H_
++#define DC_DSC_H_
++/*
++ * Copyright 2019 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Author: AMD
++ */
++struct dc_dsc_bw_range {
++ uint32_t min_kbps;
++ uint32_t min_target_bpp_x16;
++ uint32_t max_kbps;
++ uint32_t max_target_bpp_x16;
++ uint32_t stream_kbps;
++};
++
++
++bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_data,
++ struct dsc_dec_dpcd_caps *dsc_sink_caps);
++
++bool dc_dsc_compute_bandwidth_range(
++ const struct dc *dc,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_bw_range *range);
++bool dc_dsc_compute_config(
++ const struct dc *dc,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ int target_bandwidth,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_config *dsc_cfg);
++
++bool dc_check_and_fit_timing_into_bandwidth_with_dsc_legacy(
++ const struct dc *pDC,
++ const struct dc_link *link,
++ struct dc_crtc_timing *timing);
++
++bool dc_setup_dsc_in_timing_legacy(const struct dc *pDC,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ int available_bandwidth_kbps,
++ struct dc_crtc_timing *timing);
++#endif
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+index 6a9670de38f3..ea7a1c9efca8 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+@@ -709,6 +709,9 @@ struct dc_crtc_timing_flags {
+ * rates less than or equal to 340Mcsc */
+ uint32_t LTE_340MCSC_SCRAMBLE:1;
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ uint32_t DSC : 1; /* Use DSC with this timing */
++#endif
+ };
+
+ enum dc_timing_3d_format {
+@@ -755,6 +758,18 @@ struct dc_crtc_timing_adjust {
+ uint32_t v_total_max;
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++struct dc_dsc_config {
++ uint32_t num_slices_h; /* Number of DSC slices - horizontal */
++ uint32_t num_slices_v; /* Number of DSC slices - vertical */
++ uint32_t bits_per_pixel; /* DSC target bitrate in 1/16 of bpp (e.g. 128 -> 8bpp) */
++ bool block_pred_enable; /* DSC block prediction enable */
++ uint32_t linebuf_depth; /* DSC line buffer depth */
++ uint32_t version_minor; /* DSC minor version. Full version is formed as 1.version_minor. */
++ bool ycbcr422_simple; /* Tell DSC engine to convert YCbCr 4:2:2 to 'YCbCr 4:2:2 simple'. */
++ int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */
++};
++#endif
+ struct dc_crtc_timing {
+ uint32_t h_total;
+ uint32_t h_border_left;
+@@ -781,6 +796,9 @@ struct dc_crtc_timing {
+ enum scanning_type scan_type;
+
+ struct dc_crtc_timing_flags flags;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ struct dc_dsc_config dsc_cfg;
++#endif
+ };
+
+ /* Passed on init */
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
+index 094009127e25..6f0b80111e58 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
+@@ -29,6 +29,13 @@
+ #include "dc_types.h"
+ #include "grph_object_defs.h"
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++enum dc_link_fec_state {
++ dc_link_fec_not_ready,
++ dc_link_fec_ready,
++ dc_link_fec_enabled
++};
++#endif
+ struct dc_link_status {
+ bool link_active;
+ struct dpcd_caps *dpcd_caps;
+@@ -129,6 +136,9 @@ struct dc_link {
+
+ struct link_trace link_trace;
+ struct gpio *hpd_gpio;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ enum dc_link_fec_state fec_state;
++#endif
+ };
+
+ const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link);
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+index 929f155eaae7..0a83cd36d506 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+@@ -211,6 +211,9 @@ struct dc_stream_state {
+ bool apply_seamless_boot_optimization;
+
+ uint32_t stream_id;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ bool is_dsc_enabled;
++#endif
+ };
+
+ struct dc_stream_update {
+@@ -238,6 +241,9 @@ struct dc_stream_update {
+ #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
+ struct dc_writeback_update *wb_update;
+ #endif
++#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
++ struct dc_dsc_config *dsc_config;
++#endif
+ };
+
+ bool dc_is_stream_unchanged(
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
+index efeba27387c8..d755321f5437 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
+@@ -562,6 +562,9 @@ enum dc_infoframe_type {
+ DC_HDMI_INFOFRAME_TYPE_AVI = 0x82,
+ DC_HDMI_INFOFRAME_TYPE_SPD = 0x83,
+ DC_HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ DC_DP_INFOFRAME_TYPE_PPS = 0x10,
++#endif
+ };
+
+ struct dc_info_packet {
+@@ -715,4 +718,70 @@ struct AsicStateEx {
+ unsigned int phyClock;
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* DSC DPCD capabilities */
++union dsc_slice_caps1 {
++ struct {
++ uint8_t NUM_SLICES_1 : 1;
++ uint8_t NUM_SLICES_2 : 1;
++ uint8_t RESERVED : 1;
++ uint8_t NUM_SLICES_4 : 1;
++ uint8_t NUM_SLICES_6 : 1;
++ uint8_t NUM_SLICES_8 : 1;
++ uint8_t NUM_SLICES_10 : 1;
++ uint8_t NUM_SLICES_12 : 1;
++ } bits;
++ uint8_t raw;
++};
++
++union dsc_slice_caps2 {
++ struct {
++ uint8_t NUM_SLICES_16 : 1;
++ uint8_t NUM_SLICES_20 : 1;
++ uint8_t NUM_SLICES_24 : 1;
++ uint8_t RESERVED : 5;
++ } bits;
++ uint8_t raw;
++};
++
++union dsc_color_formats {
++ struct {
++ uint8_t RGB : 1;
++ uint8_t YCBCR_444 : 1;
++ uint8_t YCBCR_SIMPLE_422 : 1;
++ uint8_t YCBCR_NATIVE_422 : 1;
++ uint8_t YCBCR_NATIVE_420 : 1;
++ uint8_t RESERVED : 3;
++ } bits;
++ uint8_t raw;
++};
++
++union dsc_color_depth {
++ struct {
++ uint8_t RESERVED1 : 1;
++ uint8_t COLOR_DEPTH_8_BPC : 1;
++ uint8_t COLOR_DEPTH_10_BPC : 1;
++ uint8_t COLOR_DEPTH_12_BPC : 1;
++ uint8_t RESERVED2 : 3;
++ } bits;
++ uint8_t raw;
++};
++
++struct dsc_dec_dpcd_caps {
++ bool is_dsc_supported;
++ uint8_t dsc_version;
++ int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */
++ union dsc_slice_caps1 slice_caps1;
++ union dsc_slice_caps2 slice_caps2;
++ int32_t lb_bit_depth;
++ bool is_block_pred_supported;
++ int32_t edp_max_bits_per_pixel; /* Valid only in eDP */
++ union dsc_color_formats color_formats;
++ union dsc_color_depth color_depth;
++ int32_t throughput_mode_0_mps; /* In MPs */
++ int32_t throughput_mode_1_mps; /* In MPs */
++ int32_t max_slice_width;
++ uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */
++};
++#endif
+ #endif /* DC_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+index 9e9c2d87bab8..1c268ae4365d 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+@@ -48,6 +48,9 @@
+ #include "clk_mgr.h"
+
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#include "dsc.h"
++#endif
+
+ #define DC_LOGGER_INIT(logger)
+
+@@ -346,6 +349,61 @@ void dcn10_log_hw_state(struct dc *dc,
+ }
+ DTN_INFO("\n");
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n");
++ for (i = 0; i < pool->res_cap->num_dsc; i++) {
++ struct display_stream_compressor *dsc = pool->dscs[i];
++ struct dcn_dsc_state s = {0};
++
++ dsc->funcs->dsc_read_state(dsc, &s);
++ DTN_INFO("[%d]: %-9d %-12d %-10d\n",
++ dsc->inst,
++ s.dsc_clock_en,
++ s.dsc_slice_width,
++ s.dsc_bytes_per_pixel);
++ DTN_INFO("\n");
++ }
++ DTN_INFO("\n");
++
++ DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM"
++ " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n");
++ for (i = 0; i < pool->stream_enc_count; i++) {
++ struct stream_encoder *enc = pool->stream_enc[i];
++ struct enc_state s = {0};
++
++ if (enc->funcs->enc_read_state) {
++ enc->funcs->enc_read_state(enc, &s);
++ DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n",
++ enc->id,
++ s.dsc_mode,
++ s.sec_gsp7_line_num,
++ s.vbid6_line_reference,
++ s.vbid6_line_num,
++ s.sec_gsp7_enable,
++ s.sec_stream_enable);
++ DTN_INFO("\n");
++ }
++ }
++ DTN_INFO("\n");
++
++ DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS\n");
++ for (i = 0; i < dc->link_count; i++) {
++ struct link_encoder *lenc = dc->links[i]->link_enc;
++
++ struct link_enc_state s = {0};
++
++ if (lenc->funcs->read_state) {
++ lenc->funcs->read_state(lenc, &s);
++ DTN_INFO("[%-3d]: %-12d %-22d %-22d\n",
++ i,
++ s.dphy_fec_en,
++ s.dphy_fec_ready_shadow,
++ s.dphy_fec_active_status);
++ DTN_INFO("\n");
++ }
++ }
++ DTN_INFO("\n");
++#endif
+
+ DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n"
+ "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n",
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+index dd84fea16aea..c5b2ddb95449 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+@@ -1515,10 +1515,28 @@ void dcn10_timing_generator_init(struct optc *optc1)
+ optc1->comb_opp_id = 0xf;
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
++ *
++ * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as
++ * containter rate.
++ *
++ * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
++ * halved to maintain the correct pixel rate.
++ *
++ * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
++ * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well.
++ *
++ */
++#endif
+ bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
+ {
+ bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
++ && !timing->dsc_cfg.ycbcr422_simple);
++#endif
+ return two_pix;
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
+index 23bec3912c3c..a6299f0d6b22 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
+@@ -6,6 +6,10 @@ DCN20 = dcn20_resource.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \
+ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \
+ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o
+
++ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++DCN20 += dcn20_dsc.o
++endif
++
+
+ CFLAGS_dcn20_resource.o := -mhard-float -msse -mpreferred-stack-boundary=4
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+new file mode 100644
+index 000000000000..d17accc2e009
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+@@ -0,0 +1,688 @@
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#include "reg_helper.h"
++#include "dcn20_dsc.h"
++#include "dsc/dscc_types.h"
++
++static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps);
++static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
++ struct dsc_optc_config *dsc_optc_cfg);
++static void dsc_init_reg_values(struct dsc_reg_values *reg_vals);
++static void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params);
++static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals);
++static enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple);
++static enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth);
++
++/* Object I/F functions */
++static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz);
++static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s);
++static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg);
++static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
++ struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps);
++static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe);
++static void dsc2_disable(struct display_stream_compressor *dsc);
++
++const struct dsc_funcs dcn20_dsc_funcs = {
++ .dsc_get_enc_caps = dsc2_get_enc_caps,
++ .dsc_read_state = dsc2_read_state,
++ .dsc_validate_stream = dsc2_validate_stream,
++ .dsc_set_config = dsc2_set_config,
++ .dsc_enable = dsc2_enable,
++ .dsc_disable = dsc2_disable,
++};
++
++/* Macro definitios for REG_SET macros*/
++#define CTX \
++ dsc20->base.ctx
++
++#define REG(reg)\
++ dsc20->dsc_regs->reg
++
++#undef FN
++#define FN(reg_name, field_name) \
++ dsc20->dsc_shift->field_name, dsc20->dsc_mask->field_name
++#define DC_LOGGER \
++ dsc->ctx->logger
++
++enum dsc_bits_per_comp {
++ DSC_BPC_8 = 8,
++ DSC_BPC_10 = 10,
++ DSC_BPC_12 = 12,
++ DSC_BPC_UNKNOWN
++};
++
++/* API functions (external or via structure->function_pointer) */
++
++void dsc2_construct(struct dcn20_dsc *dsc,
++ struct dc_context *ctx,
++ int inst,
++ const struct dcn20_dsc_registers *dsc_regs,
++ const struct dcn20_dsc_shift *dsc_shift,
++ const struct dcn20_dsc_mask *dsc_mask)
++{
++ dsc->base.ctx = ctx;
++ dsc->base.inst = inst;
++ dsc->base.funcs = &dcn20_dsc_funcs;
++
++ dsc->dsc_regs = dsc_regs;
++ dsc->dsc_shift = dsc_shift;
++ dsc->dsc_mask = dsc_mask;
++}
++
++
++#define DCN20_MAX_PIXEL_CLOCK_Mhz 1188
++#define DCN20_MAX_DISPLAY_CLOCK_Mhz 1200
++
++/* This returns the capabilities for a single DSC encoder engine. Number of slices and total throughput
++ * can be doubled, tripled etc. by using additional DSC engines.
++ */
++static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz)
++{
++ dsc_enc_caps->dsc_version = 0x21; /* v1.2 - DP spec defined it in reverse order and we kept it */
++
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1;
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1;
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_3 = 1;
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1;
++
++ dsc_enc_caps->lb_bit_depth = 13;
++ dsc_enc_caps->is_block_pred_supported = true;
++
++ dsc_enc_caps->color_formats.bits.RGB = 1;
++ dsc_enc_caps->color_formats.bits.YCBCR_444 = 1;
++ dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1;
++ dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1;
++ dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1;
++
++ dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
++ dsc_enc_caps->color_depth.bits.COLOR_DEPTH_10_BPC = 1;
++ dsc_enc_caps->color_depth.bits.COLOR_DEPTH_12_BPC = 1;
++
++ /* Maximum total throughput with all the slices combined. This is different from how DP spec specifies it.
++ * Our decoder's total throughput in Pix/s is equal to DISPCLK. This is then shared between slices.
++ * The value below is the absolute maximum value. The actual througput may be lower, but it'll always
++ * be sufficient to process the input pixel rate fed into a single DSC engine.
++ */
++ dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz;
++
++ /* For pixel clock bigger than a single-pipe limit we'll need two engines, which then doubles our
++ * throughput and number of slices, but also introduces a lower limit of 2 slices
++ */
++ if (pixel_clock_100Hz >= DCN20_MAX_PIXEL_CLOCK_Mhz*10000) {
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 0;
++ dsc_enc_caps->slice_caps.bits.NUM_SLICES_8 = 1;
++ dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 2;
++ }
++
++ // TODO DSC: This is actually image width limitation, not a slice width. This should be added to the criteria to use ODM.
++ dsc_enc_caps->max_slice_width = 5184; /* (including 64 overlap pixels for eDP MSO mode) */
++ dsc_enc_caps->bpp_increment_div = 16; /* 1/16th of a bit */
++}
++
++
++/* this function read dsc related register fields to be logged later in dcn10_log_hw_state
++ * into a dcn_dsc_state struct.
++ */
++static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s)
++{
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &s->dsc_clock_en);
++ REG_GET(DSCC_PPS_CONFIG3, SLICE_WIDTH, &s->dsc_slice_width);
++ REG_GET(DSCC_PPS_CONFIG1, BITS_PER_PIXEL, &s->dsc_bytes_per_pixel);
++}
++
++
++static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg)
++{
++ struct dsc_optc_config dsc_optc_cfg;
++
++ return dsc_prepare_config(dsc, dsc_cfg, &dsc_optc_cfg);
++}
++
++
++static void dsc_config_log(struct display_stream_compressor *dsc,
++ const struct dsc_config *config)
++{
++ DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst);
++ DC_LOG_DSC("\n\tnum_slices_h %d\n\tnum_slices_v %d\n\tbits_per_pixel %d\n\tcolor_depth %d",
++ config->dc_dsc_cfg.num_slices_h,
++ config->dc_dsc_cfg.num_slices_v,
++ config->dc_dsc_cfg.bits_per_pixel,
++ config->color_depth);
++}
++
++static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
++ struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps)
++{
++ bool is_config_ok;
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ dsc_config_log(dsc, dsc_cfg);
++ is_config_ok = dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg);
++ ASSERT(is_config_ok);
++ drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc20->reg_vals.pps);
++ dsc_log_pps(dsc, &dsc20->reg_vals.pps);
++ dsc_write_to_registers(dsc, &dsc20->reg_vals);
++}
++
++
++static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe)
++{
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ /* TODO Check if DSC alreay in use? */
++ DC_LOG_DSC("enable DSC at opp pipe %d", opp_pipe);
++
++ REG_UPDATE(DSC_TOP_CONTROL,
++ DSC_CLOCK_EN, 1);
++
++ REG_UPDATE_2(DSCRM_DSC_FORWARD_CONFIG,
++ DSCRM_DSC_FORWARD_EN, 1,
++ DSCRM_DSC_OPP_PIPE_SOURCE, opp_pipe);
++}
++
++
++static void dsc2_disable(struct display_stream_compressor *dsc)
++{
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ DC_LOG_DSC("disable DSC");
++
++ REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
++ DSCRM_DSC_FORWARD_EN, 0);
++
++ REG_UPDATE(DSC_TOP_CONTROL,
++ DSC_CLOCK_EN, 0);
++}
++
++
++/* This module's internal functions */
++static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps)
++{
++ int i;
++
++ DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):");
++ DC_LOG_DSC("\tdsc_version_major %d", pps->dsc_version_major);
++ DC_LOG_DSC("\tdsc_version_minor %d", pps->dsc_version_minor);
++ DC_LOG_DSC("\tbits_per_component %d", pps->bits_per_component);
++ DC_LOG_DSC("\tline_buf_depth %d", pps->line_buf_depth);
++ DC_LOG_DSC("\tblock_pred_enable %d", pps->block_pred_enable);
++ DC_LOG_DSC("\tconvert_rgb %d", pps->convert_rgb);
++ DC_LOG_DSC("\tsimple_422 %d", pps->simple_422);
++ DC_LOG_DSC("\tvbr_enable %d", pps->vbr_enable);
++ DC_LOG_DSC("\tbits_per_pixel %d", pps->bits_per_pixel);
++ DC_LOG_DSC("\tpic_height %d", pps->pic_height);
++ DC_LOG_DSC("\tpic_width %d", pps->pic_width);
++ DC_LOG_DSC("\tslice_height %d", pps->slice_height);
++ DC_LOG_DSC("\tslice_width %d", pps->slice_width);
++ DC_LOG_DSC("\tslice_chunk_size %d", pps->slice_chunk_size);
++ DC_LOG_DSC("\tinitial_xmit_delay %d", pps->initial_xmit_delay);
++ DC_LOG_DSC("\tinitial_dec_delay %d", pps->initial_dec_delay);
++ DC_LOG_DSC("\tinitial_scale_value %d", pps->initial_scale_value);
++ DC_LOG_DSC("\tscale_increment_interval %d", pps->scale_increment_interval);
++ DC_LOG_DSC("\tscale_decrement_interval %d", pps->scale_decrement_interval);
++ DC_LOG_DSC("\tfirst_line_bpg_offset %d", pps->first_line_bpg_offset);
++ DC_LOG_DSC("\tnfl_bpg_offset %d", pps->nfl_bpg_offset);
++ DC_LOG_DSC("\tslice_bpg_offset %d", pps->slice_bpg_offset);
++ DC_LOG_DSC("\tinitial_offset %d", pps->initial_offset);
++ DC_LOG_DSC("\tfinal_offset %d", pps->final_offset);
++ DC_LOG_DSC("\tflatness_min_qp %d", pps->flatness_min_qp);
++ DC_LOG_DSC("\tflatness_max_qp %d", pps->flatness_max_qp);
++ /* DC_LOG_DSC("\trc_parameter_set %d", pps->rc_parameter_set); */
++ DC_LOG_DSC("\tnative_420 %d", pps->native_420);
++ DC_LOG_DSC("\tnative_422 %d", pps->native_422);
++ DC_LOG_DSC("\tsecond_line_bpg_offset %d", pps->second_line_bpg_offset);
++ DC_LOG_DSC("\tnsl_bpg_offset %d", pps->nsl_bpg_offset);
++ DC_LOG_DSC("\tsecond_line_offset_adj %d", pps->second_line_offset_adj);
++ DC_LOG_DSC("\trc_model_size %d", pps->rc_model_size);
++ DC_LOG_DSC("\trc_edge_factor %d", pps->rc_edge_factor);
++ DC_LOG_DSC("\trc_quant_incr_limit0 %d", pps->rc_quant_incr_limit0);
++ DC_LOG_DSC("\trc_quant_incr_limit1 %d", pps->rc_quant_incr_limit1);
++ DC_LOG_DSC("\trc_tgt_offset_high %d", pps->rc_tgt_offset_high);
++ DC_LOG_DSC("\trc_tgt_offset_low %d", pps->rc_tgt_offset_low);
++
++ for (i = 0; i < NUM_BUF_RANGES - 1; i++)
++ DC_LOG_DSC("\trc_buf_thresh[%d] %d", i, pps->rc_buf_thresh[i]);
++
++ for (i = 0; i < NUM_BUF_RANGES; i++) {
++ DC_LOG_DSC("\trc_range_parameters[%d].range_min_qp %d", i, pps->rc_range_params[i].range_min_qp);
++ DC_LOG_DSC("\trc_range_parameters[%d].range_max_qp %d", i, pps->rc_range_params[i].range_max_qp);
++ DC_LOG_DSC("\trc_range_parameters[%d].range_bpg_offset %d", i, pps->rc_range_params[i].range_bpg_offset);
++ }
++}
++
++static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
++ struct dsc_optc_config *dsc_optc_cfg)
++{
++ struct dsc_parameters dsc_params;
++
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ /* Validate input parameters */
++ ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h);
++ ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v);
++ ASSERT(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2);
++ ASSERT(dsc_cfg->pic_width);
++ ASSERT(dsc_cfg->pic_height);
++ ASSERT((dsc_cfg->dc_dsc_cfg.version_minor == 1 &&
++ (8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13)) ||
++ (dsc_cfg->dc_dsc_cfg.version_minor == 2 &&
++ ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) ||
++ dsc_cfg->dc_dsc_cfg.linebuf_depth == 0)));
++ ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375
++
++ if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_v ||
++ !(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) ||
++ !dsc_cfg->pic_width || !dsc_cfg->pic_height ||
++ !((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range:
++ 8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13) ||
++ (dsc_cfg->dc_dsc_cfg.version_minor == 2 && // v1.2 line buffer depth range:
++ ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) ||
++ dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))) ||
++ !(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff)) {
++ dm_output_to_console("%s: Invalid parameters\n", __func__);
++ return false;
++ }
++
++ dsc_init_reg_values(&dsc20->reg_vals);
++
++ /* Copy input config */
++ dsc20->reg_vals.pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple);
++ dsc20->reg_vals.num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h;
++ dsc20->reg_vals.num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v;
++ dsc20->reg_vals.pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor;
++ dsc20->reg_vals.pps.pic_width = dsc_cfg->pic_width;
++ dsc20->reg_vals.pps.pic_height = dsc_cfg->pic_height;
++ dsc20->reg_vals.pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth);
++ dsc20->reg_vals.pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable;
++ dsc20->reg_vals.pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth;
++ dsc20->reg_vals.alternate_ich_encoding_en = dsc20->reg_vals.pps.dsc_version_minor == 1 ? 0 : 1;
++
++ // TODO: in addition to validating slice height (pic height must be divisible by slice height),
++ // see what happens when the same condition doesn't apply for slice_width/pic_width.
++ dsc20->reg_vals.pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h;
++ dsc20->reg_vals.pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v;
++
++ ASSERT(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height);
++ if (!(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) {
++ dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v);
++ return false;
++ }
++
++ dsc20->reg_vals.bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1;
++ if (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422)
++ dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32;
++ else
++ dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32 >> 1;
++
++ dsc20->reg_vals.pps.convert_rgb = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB ? 1 : 0;
++ dsc20->reg_vals.pps.native_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422);
++ dsc20->reg_vals.pps.native_420 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420);
++ dsc20->reg_vals.pps.simple_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422);
++
++ if (dscc_compute_dsc_parameters(&dsc20->reg_vals.pps, &dsc_params)) {
++ dm_output_to_console("%s: DSC config failed\n", __func__);
++ return false;
++ }
++
++ dsc_update_from_dsc_parameters(&dsc20->reg_vals, &dsc_params);
++
++ dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel;
++ dsc_optc_cfg->slice_width = dsc20->reg_vals.pps.slice_width;
++ dsc_optc_cfg->is_pixel_format_444 = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB ||
++ dsc20->reg_vals.pixel_format == DSC_PIXFMT_YCBCR444 ||
++ dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422;
++
++ return true;
++}
++
++
++static enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple)
++{
++ enum dsc_pixel_format dsc_pix_fmt = DSC_PIXFMT_UNKNOWN;
++
++ /* NOTE: We don't support DSC_PIXFMT_SIMPLE_YCBCR422 */
++
++ switch (dc_pix_enc) {
++ case PIXEL_ENCODING_RGB:
++ dsc_pix_fmt = DSC_PIXFMT_RGB;
++ break;
++ case PIXEL_ENCODING_YCBCR422:
++ if (is_ycbcr422_simple)
++ dsc_pix_fmt = DSC_PIXFMT_SIMPLE_YCBCR422;
++ else
++ dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR422;
++ break;
++ case PIXEL_ENCODING_YCBCR444:
++ dsc_pix_fmt = DSC_PIXFMT_YCBCR444;
++ break;
++ case PIXEL_ENCODING_YCBCR420:
++ dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR420;
++ break;
++ default:
++ dsc_pix_fmt = DSC_PIXFMT_UNKNOWN;
++ break;
++ }
++
++ ASSERT(dsc_pix_fmt != DSC_PIXFMT_UNKNOWN);
++ return dsc_pix_fmt;
++}
++
++
++static enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth)
++{
++ enum dsc_bits_per_comp bpc = DSC_BPC_UNKNOWN;
++
++ switch (dc_color_depth) {
++ case COLOR_DEPTH_888:
++ bpc = DSC_BPC_8;
++ break;
++ case COLOR_DEPTH_101010:
++ bpc = DSC_BPC_10;
++ break;
++ case COLOR_DEPTH_121212:
++ bpc = DSC_BPC_12;
++ break;
++ default:
++ bpc = DSC_BPC_UNKNOWN;
++ break;
++ }
++
++ return bpc;
++}
++
++
++static void dsc_init_reg_values(struct dsc_reg_values *reg_vals)
++{
++ int i;
++
++ /* Non-PPS values */
++ reg_vals->dsc_clock_enable = 1;
++ reg_vals->dsc_clock_gating_disable = 0;
++ reg_vals->underflow_recovery_en = 0;
++ reg_vals->underflow_occurred_int_en = 0;
++ reg_vals->underflow_occurred_status = 0;
++ reg_vals->ich_reset_at_eol = 0;
++ reg_vals->alternate_ich_encoding_en = 0;
++ reg_vals->rc_buffer_model_size = 0;
++ reg_vals->disable_ich = 0;
++ reg_vals->dsc_dbg_en = 0;
++
++ for (i = 0; i < 4; i++)
++ reg_vals->rc_buffer_model_overflow_int_en[i] = 0;
++
++ /* PPS values */
++ reg_vals->pps.dsc_version_minor = 2;
++ reg_vals->pps.dsc_version_major = 1;
++ reg_vals->pps.line_buf_depth = 9;
++ reg_vals->pps.bits_per_component = 8;
++ reg_vals->pps.block_pred_enable = 1;
++ reg_vals->pps.slice_chunk_size = 0;
++ reg_vals->pps.pic_width = 0;
++ reg_vals->pps.pic_height = 0;
++ reg_vals->pps.slice_width = 0;
++ reg_vals->pps.slice_height = 0;
++ reg_vals->pps.initial_xmit_delay = 170;
++ reg_vals->pps.initial_dec_delay = 0;
++ reg_vals->pps.initial_scale_value = 0;
++ reg_vals->pps.scale_increment_interval = 0;
++ reg_vals->pps.scale_decrement_interval = 0;
++ reg_vals->pps.nfl_bpg_offset = 0;
++ reg_vals->pps.slice_bpg_offset = 0;
++ reg_vals->pps.nsl_bpg_offset = 0;
++ reg_vals->pps.initial_offset = 6144;
++ reg_vals->pps.final_offset = 0;
++ reg_vals->pps.flatness_min_qp = 3;
++ reg_vals->pps.flatness_max_qp = 12;
++ reg_vals->pps.rc_model_size = 8192;
++ reg_vals->pps.rc_edge_factor = 6;
++ reg_vals->pps.rc_quant_incr_limit0 = 11;
++ reg_vals->pps.rc_quant_incr_limit1 = 11;
++ reg_vals->pps.rc_tgt_offset_low = 3;
++ reg_vals->pps.rc_tgt_offset_high = 3;
++}
++
++/* Updates dsc_reg_values::reg_vals::xxx fields based on the values from computed params.
++ * This is required because dscc_compute_dsc_parameters returns a modified PPS, which in turn
++ * affects non-PPS register values.
++ */
++static void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params)
++{
++ int i;
++
++ reg_vals->pps = dsc_params->pps;
++
++ // pps_computed will have the "expanded" values; need to shift them to make them fit for regs.
++ for (i = 0; i < NUM_BUF_RANGES - 1; i++)
++ reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6;
++
++ reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size;
++ reg_vals->ich_reset_at_eol = reg_vals->num_slices_h == 1 ? 0 : 0xf;
++}
++
++static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals)
++{
++ uint32_t temp_int;
++ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
++
++ REG_SET(DSC_DEBUG_CONTROL, 0,
++ DSC_DBG_EN, reg_vals->dsc_dbg_en);
++
++ // dsccif registers
++ REG_SET_5(DSCCIF_CONFIG0, 0,
++ INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, reg_vals->underflow_recovery_en,
++ INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, reg_vals->underflow_occurred_int_en,
++ INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, reg_vals->underflow_occurred_status,
++ INPUT_PIXEL_FORMAT, reg_vals->pixel_format,
++ DSCCIF_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component);
++
++ REG_SET_2(DSCCIF_CONFIG1, 0,
++ PIC_WIDTH, reg_vals->pps.pic_width,
++ PIC_HEIGHT, reg_vals->pps.pic_height);
++
++ // dscc registers
++ REG_SET_4(DSCC_CONFIG0, 0,
++ ICH_RESET_AT_END_OF_LINE, reg_vals->ich_reset_at_eol,
++ NUMBER_OF_SLICES_PER_LINE, reg_vals->num_slices_h - 1,
++ ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en,
++ NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1);
++
++ REG_SET_2(DSCC_CONFIG1, 0,
++ DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size,
++ DSCC_DISABLE_ICH, reg_vals->disable_ich);
++
++ REG_SET_4(DSCC_INTERRUPT_CONTROL_STATUS, 0,
++ DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[0],
++ DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[1],
++ DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[2],
++ DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[3]);
++
++ REG_SET_3(DSCC_PPS_CONFIG0, 0,
++ DSC_VERSION_MINOR, reg_vals->pps.dsc_version_minor,
++ LINEBUF_DEPTH, reg_vals->pps.line_buf_depth,
++ DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component);
++
++ if (reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422)
++ temp_int = reg_vals->bpp_x32;
++ else
++ temp_int = reg_vals->bpp_x32 >> 1;
++
++ REG_SET_7(DSCC_PPS_CONFIG1, 0,
++ BITS_PER_PIXEL, temp_int,
++ SIMPLE_422, reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422,
++ CONVERT_RGB, reg_vals->pixel_format == DSC_PIXFMT_RGB,
++ BLOCK_PRED_ENABLE, reg_vals->pps.block_pred_enable,
++ NATIVE_422, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422,
++ NATIVE_420, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420,
++ CHUNK_SIZE, reg_vals->pps.slice_chunk_size);
++
++ REG_SET_2(DSCC_PPS_CONFIG2, 0,
++ PIC_WIDTH, reg_vals->pps.pic_width,
++ PIC_HEIGHT, reg_vals->pps.pic_height);
++
++ REG_SET_2(DSCC_PPS_CONFIG3, 0,
++ SLICE_WIDTH, reg_vals->pps.slice_width,
++ SLICE_HEIGHT, reg_vals->pps.slice_height);
++
++ REG_SET(DSCC_PPS_CONFIG4, 0,
++ INITIAL_XMIT_DELAY, reg_vals->pps.initial_xmit_delay);
++
++ REG_SET_2(DSCC_PPS_CONFIG5, 0,
++ INITIAL_SCALE_VALUE, reg_vals->pps.initial_scale_value,
++ SCALE_INCREMENT_INTERVAL, reg_vals->pps.scale_increment_interval);
++
++ REG_SET_3(DSCC_PPS_CONFIG6, 0,
++ SCALE_DECREMENT_INTERVAL, reg_vals->pps.scale_decrement_interval,
++ FIRST_LINE_BPG_OFFSET, reg_vals->pps.first_line_bpg_offset,
++ SECOND_LINE_BPG_OFFSET, reg_vals->pps.second_line_bpg_offset);
++
++ REG_SET_2(DSCC_PPS_CONFIG7, 0,
++ NFL_BPG_OFFSET, reg_vals->pps.nfl_bpg_offset,
++ SLICE_BPG_OFFSET, reg_vals->pps.slice_bpg_offset);
++
++ REG_SET_2(DSCC_PPS_CONFIG8, 0,
++ NSL_BPG_OFFSET, reg_vals->pps.nsl_bpg_offset,
++ SECOND_LINE_OFFSET_ADJ, reg_vals->pps.second_line_offset_adj);
++
++ REG_SET_2(DSCC_PPS_CONFIG9, 0,
++ INITIAL_OFFSET, reg_vals->pps.initial_offset,
++ FINAL_OFFSET, reg_vals->pps.final_offset);
++
++ REG_SET_3(DSCC_PPS_CONFIG10, 0,
++ FLATNESS_MIN_QP, reg_vals->pps.flatness_min_qp,
++ FLATNESS_MAX_QP, reg_vals->pps.flatness_max_qp,
++ RC_MODEL_SIZE, reg_vals->pps.rc_model_size);
++
++ REG_SET_5(DSCC_PPS_CONFIG11, 0,
++ RC_EDGE_FACTOR, reg_vals->pps.rc_edge_factor,
++ RC_QUANT_INCR_LIMIT0, reg_vals->pps.rc_quant_incr_limit0,
++ RC_QUANT_INCR_LIMIT1, reg_vals->pps.rc_quant_incr_limit1,
++ RC_TGT_OFFSET_LO, reg_vals->pps.rc_tgt_offset_low,
++ RC_TGT_OFFSET_HI, reg_vals->pps.rc_tgt_offset_high);
++
++ REG_SET_4(DSCC_PPS_CONFIG12, 0,
++ RC_BUF_THRESH0, reg_vals->pps.rc_buf_thresh[0],
++ RC_BUF_THRESH1, reg_vals->pps.rc_buf_thresh[1],
++ RC_BUF_THRESH2, reg_vals->pps.rc_buf_thresh[2],
++ RC_BUF_THRESH3, reg_vals->pps.rc_buf_thresh[3]);
++
++ REG_SET_4(DSCC_PPS_CONFIG13, 0,
++ RC_BUF_THRESH4, reg_vals->pps.rc_buf_thresh[4],
++ RC_BUF_THRESH5, reg_vals->pps.rc_buf_thresh[5],
++ RC_BUF_THRESH6, reg_vals->pps.rc_buf_thresh[6],
++ RC_BUF_THRESH7, reg_vals->pps.rc_buf_thresh[7]);
++
++ REG_SET_4(DSCC_PPS_CONFIG14, 0,
++ RC_BUF_THRESH8, reg_vals->pps.rc_buf_thresh[8],
++ RC_BUF_THRESH9, reg_vals->pps.rc_buf_thresh[9],
++ RC_BUF_THRESH10, reg_vals->pps.rc_buf_thresh[10],
++ RC_BUF_THRESH11, reg_vals->pps.rc_buf_thresh[11]);
++
++ REG_SET_5(DSCC_PPS_CONFIG15, 0,
++ RC_BUF_THRESH12, reg_vals->pps.rc_buf_thresh[12],
++ RC_BUF_THRESH13, reg_vals->pps.rc_buf_thresh[13],
++ RANGE_MIN_QP0, reg_vals->pps.rc_range_params[0].range_min_qp,
++ RANGE_MAX_QP0, reg_vals->pps.rc_range_params[0].range_max_qp,
++ RANGE_BPG_OFFSET0, reg_vals->pps.rc_range_params[0].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG16, 0,
++ RANGE_MIN_QP1, reg_vals->pps.rc_range_params[1].range_min_qp,
++ RANGE_MAX_QP1, reg_vals->pps.rc_range_params[1].range_max_qp,
++ RANGE_BPG_OFFSET1, reg_vals->pps.rc_range_params[1].range_bpg_offset,
++ RANGE_MIN_QP2, reg_vals->pps.rc_range_params[2].range_min_qp,
++ RANGE_MAX_QP2, reg_vals->pps.rc_range_params[2].range_max_qp,
++ RANGE_BPG_OFFSET2, reg_vals->pps.rc_range_params[2].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG17, 0,
++ RANGE_MIN_QP3, reg_vals->pps.rc_range_params[3].range_min_qp,
++ RANGE_MAX_QP3, reg_vals->pps.rc_range_params[3].range_max_qp,
++ RANGE_BPG_OFFSET3, reg_vals->pps.rc_range_params[3].range_bpg_offset,
++ RANGE_MIN_QP4, reg_vals->pps.rc_range_params[4].range_min_qp,
++ RANGE_MAX_QP4, reg_vals->pps.rc_range_params[4].range_max_qp,
++ RANGE_BPG_OFFSET4, reg_vals->pps.rc_range_params[4].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG18, 0,
++ RANGE_MIN_QP5, reg_vals->pps.rc_range_params[5].range_min_qp,
++ RANGE_MAX_QP5, reg_vals->pps.rc_range_params[5].range_max_qp,
++ RANGE_BPG_OFFSET5, reg_vals->pps.rc_range_params[5].range_bpg_offset,
++ RANGE_MIN_QP6, reg_vals->pps.rc_range_params[6].range_min_qp,
++ RANGE_MAX_QP6, reg_vals->pps.rc_range_params[6].range_max_qp,
++ RANGE_BPG_OFFSET6, reg_vals->pps.rc_range_params[6].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG19, 0,
++ RANGE_MIN_QP7, reg_vals->pps.rc_range_params[7].range_min_qp,
++ RANGE_MAX_QP7, reg_vals->pps.rc_range_params[7].range_max_qp,
++ RANGE_BPG_OFFSET7, reg_vals->pps.rc_range_params[7].range_bpg_offset,
++ RANGE_MIN_QP8, reg_vals->pps.rc_range_params[8].range_min_qp,
++ RANGE_MAX_QP8, reg_vals->pps.rc_range_params[8].range_max_qp,
++ RANGE_BPG_OFFSET8, reg_vals->pps.rc_range_params[8].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG20, 0,
++ RANGE_MIN_QP9, reg_vals->pps.rc_range_params[9].range_min_qp,
++ RANGE_MAX_QP9, reg_vals->pps.rc_range_params[9].range_max_qp,
++ RANGE_BPG_OFFSET9, reg_vals->pps.rc_range_params[9].range_bpg_offset,
++ RANGE_MIN_QP10, reg_vals->pps.rc_range_params[10].range_min_qp,
++ RANGE_MAX_QP10, reg_vals->pps.rc_range_params[10].range_max_qp,
++ RANGE_BPG_OFFSET10, reg_vals->pps.rc_range_params[10].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG21, 0,
++ RANGE_MIN_QP11, reg_vals->pps.rc_range_params[11].range_min_qp,
++ RANGE_MAX_QP11, reg_vals->pps.rc_range_params[11].range_max_qp,
++ RANGE_BPG_OFFSET11, reg_vals->pps.rc_range_params[11].range_bpg_offset,
++ RANGE_MIN_QP12, reg_vals->pps.rc_range_params[12].range_min_qp,
++ RANGE_MAX_QP12, reg_vals->pps.rc_range_params[12].range_max_qp,
++ RANGE_BPG_OFFSET12, reg_vals->pps.rc_range_params[12].range_bpg_offset);
++
++ REG_SET_6(DSCC_PPS_CONFIG22, 0,
++ RANGE_MIN_QP13, reg_vals->pps.rc_range_params[13].range_min_qp,
++ RANGE_MAX_QP13, reg_vals->pps.rc_range_params[13].range_max_qp,
++ RANGE_BPG_OFFSET13, reg_vals->pps.rc_range_params[13].range_bpg_offset,
++ RANGE_MIN_QP14, reg_vals->pps.rc_range_params[14].range_min_qp,
++ RANGE_MAX_QP14, reg_vals->pps.rc_range_params[14].range_max_qp,
++ RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset);
++
++ if (IS_FPGA_MAXIMUS_DC(dsc20->base.ctx->dce_environment)) {
++ /* It's safe to do this as long as debug bus is not being used in DAL Diag environment.
++ *
++ * This is because DSCC_PPS_CONFIG4.INITIAL_DEC_DELAY is a read-only register field (because it's a decoder
++ * value not required by DSC encoder). However, since decoding fails when this value is missing from PPS, it's
++ * required to communicate this value to the PPS header. When testing on FPGA, the values for PPS header are
++ * being read from Diag register dump. The register below is used in place of a scratch register to make
++ * 'initial_dec_delay' available.
++ */
++
++ temp_int = reg_vals->pps.initial_dec_delay;
++ REG_SET_4(DSCC_TEST_DEBUG_BUS_ROTATE, 0,
++ DSCC_TEST_DEBUG_BUS0_ROTATE, temp_int & 0x1f,
++ DSCC_TEST_DEBUG_BUS1_ROTATE, temp_int >> 5 & 0x1f,
++ DSCC_TEST_DEBUG_BUS2_ROTATE, temp_int >> 10 & 0x1f,
++ DSCC_TEST_DEBUG_BUS3_ROTATE, temp_int >> 15 & 0x1);
++ }
++}
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
+new file mode 100644
+index 000000000000..5cbb9df8272f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
+@@ -0,0 +1,573 @@
++/* Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#ifndef __DCN20_DSC_H__
++#define __DCN20_DSC_H__
++
++#include "dsc.h"
++#include "dsc/dscc_types.h"
++#include <drm/drm_dsc.h>
++
++#define TO_DCN20_DSC(dsc)\
++ container_of(dsc, struct dcn20_dsc, base)
++
++#define DSC_REG_LIST_DCN20(id) \
++ SRI(DSC_TOP_CONTROL, DSC_TOP, id),\
++ SRI(DSC_DEBUG_CONTROL, DSC_TOP, id),\
++ SRI(DSCC_CONFIG0, DSCC, id),\
++ SRI(DSCC_CONFIG1, DSCC, id),\
++ SRI(DSCC_STATUS, DSCC, id),\
++ SRI(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG0, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG1, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG2, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG3, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG4, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG5, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG6, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG7, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG8, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG9, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG10, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG11, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG12, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG13, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG14, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG15, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG16, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG17, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG18, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG19, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG20, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG21, DSCC, id),\
++ SRI(DSCC_PPS_CONFIG22, DSCC, id),\
++ SRI(DSCC_MEM_POWER_CONTROL, DSCC, id),\
++ SRI(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id),\
++ SRI(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id),\
++ SRI(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id),\
++ SRI(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id),\
++ SRI(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id),\
++ SRI(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id),\
++ SRI(DSCC_MAX_ABS_ERROR0, DSCC, id),\
++ SRI(DSCC_MAX_ABS_ERROR1, DSCC, id),\
++ SRI(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\
++ SRI(DSCC_TEST_DEBUG_BUS_ROTATE, DSCC, id),\
++ SRI(DSCCIF_CONFIG0, DSCCIF, id),\
++ SRI(DSCCIF_CONFIG1, DSCCIF, id),\
++ SRI(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id)
++
++
++#define DSC_SF(reg_name, field_name, post_fix)\
++ .field_name = reg_name ## __ ## field_name ## post_fix
++
++//Used in resolving the corner case with duplicate field name
++#define DSC2_SF(reg_name, field_name, post_fix)\
++ .field_name = reg_name ## _ ## field_name ## post_fix
++
++#define DSC_REG_LIST_SH_MASK_DCN20(mask_sh)\
++ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \
++ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \
++ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \
++ DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \
++ DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_TEST_CLOCK_MUX_SEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh), \
++ DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \
++ DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \
++ DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_FORCE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_DIS, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_STATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_FORCE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_DIS, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_STATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC_R_Y_SQUARED_ERROR_LOWER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC_R_Y_SQUARED_ERROR_UPPER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC_G_CB_SQUARED_ERROR_LOWER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC_G_CB_SQUARED_ERROR_UPPER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC_B_CR_SQUARED_ERROR_LOWER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC_B_CR_SQUARED_ERROR_UPPER, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_R_Y_MAX_ABS_ERROR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_G_CB_MAX_ABS_ERROR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR1, DSCC_B_CR_MAX_ABS_ERROR, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \
++ DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS0_ROTATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS1_ROTATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS2_ROTATE, mask_sh), \
++ DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS3_ROTATE, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_PIXEL_FORMAT, mask_sh), \
++ DSC2_SF(DSCCIF0, DSCCIF_CONFIG0__BITS_PER_COMPONENT, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG0, DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_WIDTH, mask_sh), \
++ DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_HEIGHT, mask_sh), \
++ DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \
++ DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh)
++
++
++
++#define DSC_FIELD_LIST_DCN20(type)\
++ type DSC_CLOCK_EN; \
++ type DSC_DISPCLK_R_GATE_DIS; \
++ type DSC_DSCCLK_R_GATE_DIS; \
++ type DSC_DBG_EN; \
++ type DSC_TEST_CLOCK_MUX_SEL; \
++ type ICH_RESET_AT_END_OF_LINE; \
++ type NUMBER_OF_SLICES_PER_LINE; \
++ type ALTERNATE_ICH_ENCODING_EN; \
++ type NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE; \
++ type DSCC_DISABLE_ICH; \
++ type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \
++ type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED; \
++ type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN; \
++ type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN; \
++ type DSC_VERSION_MINOR; \
++ type DSC_VERSION_MAJOR; \
++ type PPS_IDENTIFIER; \
++ type LINEBUF_DEPTH; \
++ type DSCC_PPS_CONFIG0__BITS_PER_COMPONENT; \
++ type BITS_PER_PIXEL; \
++ type VBR_ENABLE; \
++ type SIMPLE_422; \
++ type CONVERT_RGB; \
++ type BLOCK_PRED_ENABLE; \
++ type NATIVE_422; \
++ type NATIVE_420; \
++ type CHUNK_SIZE; \
++ type PIC_WIDTH; \
++ type PIC_HEIGHT; \
++ type SLICE_WIDTH; \
++ type SLICE_HEIGHT; \
++ type INITIAL_XMIT_DELAY; \
++ type INITIAL_DEC_DELAY; \
++ type INITIAL_SCALE_VALUE; \
++ type SCALE_INCREMENT_INTERVAL; \
++ type SCALE_DECREMENT_INTERVAL; \
++ type FIRST_LINE_BPG_OFFSET; \
++ type SECOND_LINE_BPG_OFFSET; \
++ type NFL_BPG_OFFSET; \
++ type SLICE_BPG_OFFSET; \
++ type NSL_BPG_OFFSET; \
++ type SECOND_LINE_OFFSET_ADJ; \
++ type INITIAL_OFFSET; \
++ type FINAL_OFFSET; \
++ type FLATNESS_MIN_QP; \
++ type FLATNESS_MAX_QP; \
++ type RC_MODEL_SIZE; \
++ type RC_EDGE_FACTOR; \
++ type RC_QUANT_INCR_LIMIT0; \
++ type RC_QUANT_INCR_LIMIT1; \
++ type RC_TGT_OFFSET_LO; \
++ type RC_TGT_OFFSET_HI; \
++ type RC_BUF_THRESH0; \
++ type RC_BUF_THRESH1; \
++ type RC_BUF_THRESH2; \
++ type RC_BUF_THRESH3; \
++ type RC_BUF_THRESH4; \
++ type RC_BUF_THRESH5; \
++ type RC_BUF_THRESH6; \
++ type RC_BUF_THRESH7; \
++ type RC_BUF_THRESH8; \
++ type RC_BUF_THRESH9; \
++ type RC_BUF_THRESH10; \
++ type RC_BUF_THRESH11; \
++ type RC_BUF_THRESH12; \
++ type RC_BUF_THRESH13; \
++ type RANGE_MIN_QP0; \
++ type RANGE_MAX_QP0; \
++ type RANGE_BPG_OFFSET0; \
++ type RANGE_MIN_QP1; \
++ type RANGE_MAX_QP1; \
++ type RANGE_BPG_OFFSET1; \
++ type RANGE_MIN_QP2; \
++ type RANGE_MAX_QP2; \
++ type RANGE_BPG_OFFSET2; \
++ type RANGE_MIN_QP3; \
++ type RANGE_MAX_QP3; \
++ type RANGE_BPG_OFFSET3; \
++ type RANGE_MIN_QP4; \
++ type RANGE_MAX_QP4; \
++ type RANGE_BPG_OFFSET4; \
++ type RANGE_MIN_QP5; \
++ type RANGE_MAX_QP5; \
++ type RANGE_BPG_OFFSET5; \
++ type RANGE_MIN_QP6; \
++ type RANGE_MAX_QP6; \
++ type RANGE_BPG_OFFSET6; \
++ type RANGE_MIN_QP7; \
++ type RANGE_MAX_QP7; \
++ type RANGE_BPG_OFFSET7; \
++ type RANGE_MIN_QP8; \
++ type RANGE_MAX_QP8; \
++ type RANGE_BPG_OFFSET8; \
++ type RANGE_MIN_QP9; \
++ type RANGE_MAX_QP9; \
++ type RANGE_BPG_OFFSET9; \
++ type RANGE_MIN_QP10; \
++ type RANGE_MAX_QP10; \
++ type RANGE_BPG_OFFSET10; \
++ type RANGE_MIN_QP11; \
++ type RANGE_MAX_QP11; \
++ type RANGE_BPG_OFFSET11; \
++ type RANGE_MIN_QP12; \
++ type RANGE_MAX_QP12; \
++ type RANGE_BPG_OFFSET12; \
++ type RANGE_MIN_QP13; \
++ type RANGE_MAX_QP13; \
++ type RANGE_BPG_OFFSET13; \
++ type RANGE_MIN_QP14; \
++ type RANGE_MAX_QP14; \
++ type RANGE_BPG_OFFSET14; \
++ type DSCC_DEFAULT_MEM_LOW_POWER_STATE; \
++ type DSCC_MEM_PWR_FORCE; \
++ type DSCC_MEM_PWR_DIS; \
++ type DSCC_MEM_PWR_STATE; \
++ type DSCC_NATIVE_422_MEM_PWR_FORCE; \
++ type DSCC_NATIVE_422_MEM_PWR_DIS; \
++ type DSCC_NATIVE_422_MEM_PWR_STATE; \
++ type DSCC_R_Y_SQUARED_ERROR_LOWER; \
++ type DSCC_R_Y_SQUARED_ERROR_UPPER; \
++ type DSCC_G_CB_SQUARED_ERROR_LOWER; \
++ type DSCC_G_CB_SQUARED_ERROR_UPPER; \
++ type DSCC_B_CR_SQUARED_ERROR_LOWER; \
++ type DSCC_B_CR_SQUARED_ERROR_UPPER; \
++ type DSCC_R_Y_MAX_ABS_ERROR; \
++ type DSCC_G_CB_MAX_ABS_ERROR; \
++ type DSCC_B_CR_MAX_ABS_ERROR; \
++ type DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; \
++ type DSCC_UPDATE_PENDING_STATUS; \
++ type DSCC_UPDATE_TAKEN_STATUS; \
++ type DSCC_UPDATE_TAKEN_ACK; \
++ type DSCC_TEST_DEBUG_BUS0_ROTATE; \
++ type DSCC_TEST_DEBUG_BUS1_ROTATE; \
++ type DSCC_TEST_DEBUG_BUS2_ROTATE; \
++ type DSCC_TEST_DEBUG_BUS3_ROTATE; \
++ type DSCC_RATE_BUFFER0_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER1_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER2_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER3_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER0_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER1_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER2_FULLNESS_LEVEL; \
++ type DSCC_RATE_CONTROL_BUFFER3_FULLNESS_LEVEL; \
++ type DSCC_RATE_BUFFER0_INITIAL_XMIT_DELAY_REACHED; \
++ type DSCC_RATE_BUFFER1_INITIAL_XMIT_DELAY_REACHED; \
++ type DSCC_RATE_BUFFER2_INITIAL_XMIT_DELAY_REACHED; \
++ type DSCC_RATE_BUFFER3_INITIAL_XMIT_DELAY_REACHED; \
++ type INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN; \
++ type INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN; \
++ type INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS; \
++ type INPUT_PIXEL_FORMAT; \
++ type DSCCIF_CONFIG0__BITS_PER_COMPONENT; \
++ type DOUBLE_BUFFER_REG_UPDATE_PENDING; \
++ type DSCCIF_UPDATE_PENDING_STATUS; \
++ type DSCCIF_UPDATE_TAKEN_STATUS; \
++ type DSCCIF_UPDATE_TAKEN_ACK; \
++ type DSCRM_DSC_FORWARD_EN; \
++ type DSCRM_DSC_OPP_PIPE_SOURCE
++
++
++struct dcn20_dsc_registers {
++ uint32_t DSC_TOP_CONTROL;
++ uint32_t DSC_DEBUG_CONTROL;
++ uint32_t DSCC_CONFIG0;
++ uint32_t DSCC_CONFIG1;
++ uint32_t DSCC_STATUS;
++ uint32_t DSCC_INTERRUPT_CONTROL_STATUS;
++ uint32_t DSCC_PPS_CONFIG0;
++ uint32_t DSCC_PPS_CONFIG1;
++ uint32_t DSCC_PPS_CONFIG2;
++ uint32_t DSCC_PPS_CONFIG3;
++ uint32_t DSCC_PPS_CONFIG4;
++ uint32_t DSCC_PPS_CONFIG5;
++ uint32_t DSCC_PPS_CONFIG6;
++ uint32_t DSCC_PPS_CONFIG7;
++ uint32_t DSCC_PPS_CONFIG8;
++ uint32_t DSCC_PPS_CONFIG9;
++ uint32_t DSCC_PPS_CONFIG10;
++ uint32_t DSCC_PPS_CONFIG11;
++ uint32_t DSCC_PPS_CONFIG12;
++ uint32_t DSCC_PPS_CONFIG13;
++ uint32_t DSCC_PPS_CONFIG14;
++ uint32_t DSCC_PPS_CONFIG15;
++ uint32_t DSCC_PPS_CONFIG16;
++ uint32_t DSCC_PPS_CONFIG17;
++ uint32_t DSCC_PPS_CONFIG18;
++ uint32_t DSCC_PPS_CONFIG19;
++ uint32_t DSCC_PPS_CONFIG20;
++ uint32_t DSCC_PPS_CONFIG21;
++ uint32_t DSCC_PPS_CONFIG22;
++ uint32_t DSCC_MEM_POWER_CONTROL;
++ uint32_t DSCC_R_Y_SQUARED_ERROR_LOWER;
++ uint32_t DSCC_R_Y_SQUARED_ERROR_UPPER;
++ uint32_t DSCC_G_CB_SQUARED_ERROR_LOWER;
++ uint32_t DSCC_G_CB_SQUARED_ERROR_UPPER;
++ uint32_t DSCC_B_CR_SQUARED_ERROR_LOWER;
++ uint32_t DSCC_B_CR_SQUARED_ERROR_UPPER;
++ uint32_t DSCC_MAX_ABS_ERROR0;
++ uint32_t DSCC_MAX_ABS_ERROR1;
++ uint32_t DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL;
++ uint32_t DSCC_TEST_DEBUG_BUS_ROTATE;
++ uint32_t DSCCIF_CONFIG0;
++ uint32_t DSCCIF_CONFIG1;
++ uint32_t DSCRM_DSC_FORWARD_CONFIG;
++};
++
++
++struct dcn20_dsc_shift {
++ DSC_FIELD_LIST_DCN20(uint8_t);
++};
++
++struct dcn20_dsc_mask {
++ DSC_FIELD_LIST_DCN20(uint32_t);
++};
++
++/* DSCCIF_CONFIG.INPUT_PIXEL_FORMAT values */
++enum dsc_pixel_format {
++ DSC_PIXFMT_RGB,
++ DSC_PIXFMT_YCBCR444,
++ DSC_PIXFMT_SIMPLE_YCBCR422,
++ DSC_PIXFMT_NATIVE_YCBCR422,
++ DSC_PIXFMT_NATIVE_YCBCR420,
++ DSC_PIXFMT_UNKNOWN
++};
++
++struct dsc_reg_values {
++ /* PPS registers */
++ struct drm_dsc_config pps;
++
++ /* Additional registers */
++ uint32_t dsc_clock_enable;
++ uint32_t dsc_clock_gating_disable;
++ uint32_t underflow_recovery_en;
++ uint32_t underflow_occurred_int_en;
++ uint32_t underflow_occurred_status;
++ enum dsc_pixel_format pixel_format;
++ uint32_t ich_reset_at_eol;
++ uint32_t alternate_ich_encoding_en;
++ uint32_t num_slices_h;
++ uint32_t num_slices_v;
++ uint32_t rc_buffer_model_size;
++ uint32_t disable_ich;
++ uint32_t bpp_x32;
++ uint32_t dsc_dbg_en;
++ uint32_t rc_buffer_model_overflow_int_en[4];
++};
++
++struct dcn20_dsc {
++ struct display_stream_compressor base;
++ const struct dcn20_dsc_registers *dsc_regs;
++ const struct dcn20_dsc_shift *dsc_shift;
++ const struct dcn20_dsc_mask *dsc_mask;
++
++ struct dsc_reg_values reg_vals;
++};
++
++
++void dsc2_construct(struct dcn20_dsc *dsc,
++ struct dc_context *ctx,
++ int inst,
++ const struct dcn20_dsc_registers *dsc_regs,
++ const struct dcn20_dsc_shift *dsc_shift,
++ const struct dcn20_dsc_mask *dsc_mask);
++
++#endif
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+index 3d5eb20ea9ba..1fd89cc218a5 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+@@ -32,6 +32,9 @@
+ #include "dcn10/dcn10_hw_sequencer.h"
+ #include "dcn20_hwseq.h"
+ #include "dce/dce_hwseq.h"
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#include "dcn20/dcn20_dsc.h"
++#endif
+ #include "abm.h"
+ #include "clk_mgr.h"
+ #include "dmcu.h"
+@@ -211,6 +214,76 @@ static void dcn20_init_blank(
+ dcn20_hwss_wait_for_blank_complete(opp);
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++static void dcn20_dsc_pg_control(
++ struct dce_hwseq *hws,
++ unsigned int dsc_inst,
++ bool power_on)
++{
++ uint32_t power_gate = power_on ? 0 : 1;
++ uint32_t pwr_status = power_on ? 0 : 2;
++
++ if (hws->ctx->dc->debug.disable_dsc_power_gate)
++ return;
++
++ if (REG(DOMAIN16_PG_CONFIG) == 0)
++ return;
++
++ switch (dsc_inst) {
++ case 0: /* DSC0 */
++ REG_UPDATE(DOMAIN16_PG_CONFIG,
++ DOMAIN16_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN16_PG_STATUS,
++ DOMAIN16_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ case 1: /* DSC1 */
++ REG_UPDATE(DOMAIN17_PG_CONFIG,
++ DOMAIN17_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN17_PG_STATUS,
++ DOMAIN17_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ case 2: /* DSC2 */
++ REG_UPDATE(DOMAIN18_PG_CONFIG,
++ DOMAIN18_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN18_PG_STATUS,
++ DOMAIN18_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ case 3: /* DSC3 */
++ REG_UPDATE(DOMAIN19_PG_CONFIG,
++ DOMAIN19_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN19_PG_STATUS,
++ DOMAIN19_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ case 4: /* DSC4 */
++ REG_UPDATE(DOMAIN20_PG_CONFIG,
++ DOMAIN20_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN20_PG_STATUS,
++ DOMAIN20_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ case 5: /* DSC5 */
++ REG_UPDATE(DOMAIN21_PG_CONFIG,
++ DOMAIN21_POWER_GATE, power_gate);
++
++ REG_WAIT(DOMAIN21_PG_STATUS,
++ DOMAIN21_PGFSM_PWR_STATUS, pwr_status,
++ 1, 1000);
++ break;
++ default:
++ BREAK_TO_DEBUGGER();
++ break;
++ }
++}
++#endif
+
+ static void dcn20_dpp_pg_control(
+ struct dce_hwseq *hws,
+@@ -1457,10 +1530,30 @@ bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
+
+ static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
+ {
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ struct dce_hwseq *hws = dc->hwseq;
++ struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
++
++ if (pipe_ctx->stream_res.dsc) {
++ dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
++ if (bot_odm_pipe)
++ dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true);
++ }
++#endif
+ }
+
+ static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
+ {
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ struct dce_hwseq *hws = dc->hwseq;
++ struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
++
++ if (pipe_ctx->stream_res.dsc) {
++ dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
++ if (bot_odm_pipe)
++ dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false);
++ }
++#endif
+ }
+
+ void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
+index 290ebaacbabe..6f7af235dd79 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
+@@ -168,6 +168,10 @@ static struct mpll_cfg dcn2_mpll_cfg[] = {
+ void enc2_fec_set_enable(struct link_encoder *enc, bool enable)
+ {
+ struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ DC_LOG_DSC("%s FEC at link encoder inst %d",
++ enable ? "Enabling" : "Disabling", enc->id.enum_id);
++#endif
+ REG_UPDATE(DP_DPHY_CNTL, DPHY_FEC_EN, enable);
+ }
+
+@@ -188,6 +192,19 @@ bool enc2_fec_is_active(struct link_encoder *enc)
+ return (active != 0);
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* this function reads dsc related register fields to be logged later in dcn10_log_hw_state
++ * into a dcn_dsc_state struct.
++ */
++void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s)
++{
++ struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
++
++ REG_GET(DP_DPHY_CNTL, DPHY_FEC_EN, &s->dphy_fec_en);
++ REG_GET(DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, &s->dphy_fec_ready_shadow);
++ REG_GET(DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, &s->dphy_fec_active_status);
++}
++#endif
+
+ static bool update_cfg_data(
+ struct dcn10_link_encoder *enc10,
+@@ -298,6 +315,9 @@ void enc2_hw_init(struct link_encoder *enc)
+ }
+
+ static const struct link_encoder_funcs dcn20_link_enc_funcs = {
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .read_state = link_enc2_read_state,
++#endif
+ .validate_output_with_stream =
+ dcn10_link_encoder_validate_output_with_stream,
+ .hw_init = enc2_hw_init,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h
+index c67755779079..401fdea77262 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h
+@@ -151,6 +151,9 @@ void enc2_fec_set_ready(struct link_encoder *enc, bool ready);
+ bool enc2_fec_is_active(struct link_encoder *enc);
+ void enc2_hw_init(struct link_encoder *enc);
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s);
++#endif
+
+ void dcn20_link_encoder_construct(
+ struct dcn20_link_encoder *enc20,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+index 72d72c3a35ee..875b48e450f8 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+@@ -167,6 +167,41 @@ void optc2_set_gsl_source_select(
+ }
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* DSC encoder frame start controls: x = h position, line_num = # of lines from vstartup */
++void optc2_set_dsc_encoder_frame_start(struct timing_generator *optc,
++ int x_position,
++ int line_num)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET_2(OTG_DSC_START_POSITION, 0,
++ OTG_DSC_START_POSITION_X, x_position,
++ OTG_DSC_START_POSITION_LINE_NUM, line_num);
++}
++
++/* Set DSC-related configuration.
++ * dsc_mode: 0 disables DSC, other values enable DSC in specified format
++ * sc_bytes_per_pixel: Bytes per pixel in u3.28 format
++ * dsc_slice_width: Slice width in pixels
++ */
++void optc2_set_dsc_config(struct timing_generator *optc,
++ enum optc_dsc_mode dsc_mode,
++ uint32_t dsc_bytes_per_pixel,
++ uint32_t dsc_slice_width)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_UPDATE(OPTC_DATA_FORMAT_CONTROL,
++ OPTC_DSC_MODE, dsc_mode);
++
++ REG_SET(OPTC_BYTES_PER_PIXEL, 0,
++ OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel);
++
++ REG_UPDATE(OPTC_WIDTH_CONTROL,
++ OPTC_DSC_SLICE_WIDTH, dsc_slice_width);
++}
++#endif
+
+ /**
+ * PTI i think is already done somewhere else for 2ka
+@@ -390,6 +425,9 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
+ .setup_global_swap_lock = NULL,
+ .get_crc = optc1_get_crc,
+ .configure_crc = optc1_configure_crc,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .set_dsc_config = optc2_set_dsc_config,
++#endif
+ .set_dwb_source = optc2_set_dwb_source,
+ .set_odm_bypass = optc2_set_odm_bypass,
+ .set_odm_combine = optc2_set_odm_combine,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
+index fe851049aa9b..b936a4da1583 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
+@@ -83,6 +83,12 @@ void optc2_set_gsl_source_select(struct timing_generator *optc,
+ int group_idx,
+ uint32_t gsl_ready_signal);
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++void optc2_set_dsc_config(struct timing_generator *optc,
++ enum optc_dsc_mode dsc_mode,
++ uint32_t dsc_bytes_per_pixel,
++ uint32_t dsc_slice_width);
++#endif
+
+ void optc2_set_odm_bypass(struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing);
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+index af4e2447a5da..d0c279ab0af1 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+@@ -42,6 +42,10 @@
+ #include "dce110/dce110_hw_sequencer.h"
+ #include "dcn20_opp.h"
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#include "dcn20_dsc.h"
++#endif
++
+ #include "dcn20_link_encoder.h"
+ #include "dcn20_stream_encoder.h"
+ #include "dce/dce_clock_source.h"
+@@ -83,7 +87,11 @@ struct _vcs_dpi_ip_params_st dcn2_0_ip = {
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .pte_group_size_bytes = 2048,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .num_dsc = 6,
++#else
+ .num_dsc = 0,
++#endif
+ .rob_buffer_size_kbytes = 168,
+ .det_buffer_size_kbytes = 164,
+ .dpte_buffer_size_in_pte_reqs_luma = 84,
+@@ -572,6 +580,29 @@ static const struct dcn20_vmid_mask vmid_masks = {
+ DCN20_VMID_MASK_SH_LIST(_MASK)
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#define dsc_regsDCN20(id)\
++[id] = {\
++ DSC_REG_LIST_DCN20(id)\
++}
++
++static const struct dcn20_dsc_registers dsc_regs[] = {
++ dsc_regsDCN20(0),
++ dsc_regsDCN20(1),
++ dsc_regsDCN20(2),
++ dsc_regsDCN20(3),
++ dsc_regsDCN20(4),
++ dsc_regsDCN20(5)
++};
++
++static const struct dcn20_dsc_shift dsc_shift = {
++ DSC_REG_LIST_SH_MASK_DCN20(__SHIFT)
++};
++
++static const struct dcn20_dsc_mask dsc_mask = {
++ DSC_REG_LIST_SH_MASK_DCN20(_MASK)
++};
++#endif
+
+ static const struct dccg_registers dccg_regs = {
+ DCCG_REG_LIST_DCN2()
+@@ -595,6 +626,9 @@ static const struct resource_caps res_cap_nv10 = {
+ .num_dwb = 1,
+ .num_ddc = 6,
+ .num_vmid = 16,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .num_dsc = 6,
++#endif
+ };
+
+ static const struct dc_plane_cap plane_cap = {
+@@ -961,6 +995,30 @@ void dcn20_clock_source_destroy(struct clock_source **clk_src)
+ *clk_src = NULL;
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++
++struct display_stream_compressor *dcn20_dsc_create(
++ struct dc_context *ctx, uint32_t inst)
++{
++ struct dcn20_dsc *dsc =
++ kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL);
++
++ if (!dsc) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask);
++ return &dsc->base;
++}
++
++void dcn20_dsc_destroy(struct display_stream_compressor **dsc)
++{
++ kfree(container_of(*dsc, struct dcn20_dsc, base));
++ *dsc = NULL;
++}
++
++#endif
+
+ static void destruct(struct dcn20_resource_pool *pool)
+ {
+@@ -973,6 +1031,12 @@ static void destruct(struct dcn20_resource_pool *pool)
+ }
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
++ if (pool->base.dscs[i] != NULL)
++ dcn20_dsc_destroy(&pool->base.dscs[i]);
++ }
++#endif
+
+ if (pool->base.mpc != NULL) {
+ kfree(TO_DCN20_MPC(pool->base.mpc));
+@@ -1164,6 +1228,39 @@ enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state
+ return status;
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++
++static struct display_stream_compressor *acquire_dsc(struct resource_context *res_ctx,
++ const struct resource_pool *pool)
++{
++ int i;
++ struct display_stream_compressor *dsc = NULL;
++
++ /* Find first free DSC */
++ for (i = 0; i < pool->res_cap->num_dsc; i++)
++ if (!res_ctx->is_dsc_acquired[i]) {
++ dsc = pool->dscs[i];
++ res_ctx->is_dsc_acquired[i] = true;
++ break;
++ }
++
++ return dsc;
++}
++
++static void release_dsc(struct resource_context *res_ctx,
++ const struct resource_pool *pool,
++ const struct display_stream_compressor *dsc)
++{
++ int i;
++
++ for (i = 0; i < pool->res_cap->num_dsc; i++)
++ if (pool->dscs[i] == dsc) {
++ res_ctx->is_dsc_acquired[i] = false;
++ break;
++ }
++}
++
++#endif
+
+ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream)
+ {
+@@ -1174,6 +1271,33 @@ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx,
+ if (result == DC_OK)
+ result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream);
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ /* Get a DSC if required and available */
++ if (result == DC_OK) {
++ int i;
++ const struct resource_pool *pool = dc->res_pool;
++ bool is_add_dsc = true;
++
++ for (i = 0; i < dc->res_pool->pipe_count; i++) {
++ struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i];
++
++ if (pipe_ctx->stream != dc_stream)
++ continue;
++
++ if (is_add_dsc) {
++ pipe_ctx->stream_res.dsc = acquire_dsc(&new_ctx->res_ctx, pool);
++
++ /* The number of DSCs can be less than the number of pipes */
++ if (!pipe_ctx->stream_res.dsc) {
++ dm_output_to_console("No DSCs available\n");
++ result = DC_NO_DSC_RESOURCE;
++ }
++ }
++
++ break;
++ }
++ }
++#endif
+
+ if (result == DC_OK)
+ result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream);
+@@ -1198,6 +1322,18 @@ enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_
+ if (!pipe_ctx)
+ return DC_ERROR_UNEXPECTED;
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ if (pipe_ctx->stream_res.dsc) {
++ struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
++
++ release_dsc(&new_ctx->res_ctx, dc->res_pool, pipe_ctx->stream_res.dsc);
++ pipe_ctx->stream_res.dsc = NULL;
++ if (odm_pipe) {
++ release_dsc(&new_ctx->res_ctx, dc->res_pool, odm_pipe->stream_res.dsc);
++ odm_pipe->stream_res.dsc = NULL;
++ }
++ }
++#endif
+
+ return DC_OK;
+ }
+@@ -1331,6 +1467,14 @@ static bool dcn20_split_stream_for_combine(
+ sd->recout.x = 0;
+ }
+ secondary_pipe->stream_res.opp = pool->opps[secondary_pipe->pipe_idx];
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ if (is_add_dsc) {
++ secondary_pipe->stream_res.dsc = acquire_dsc(res_ctx, pool);
++ ASSERT(secondary_pipe->stream_res.dsc);
++ if (secondary_pipe->stream_res.dsc == NULL)
++ return false;
++ }
++#endif
+ } else {
+ ASSERT(primary_pipe->plane_state);
+ resource_build_scaling_params(primary_pipe);
+@@ -1410,6 +1554,11 @@ int dcn20_populate_dml_pipes_from_context(
+ pipes[pipe_cnt].pipe.src.dcc = 0;
+ pipes[pipe_cnt].pipe.src.vm = 0;*/
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC;
++ /* todo: rotation?*/
++ pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h;
++#endif
+ if (res_ctx->pipe_ctx[i].stream->use_dynamic_meta) {
+ pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = true;
+ /* 1/2 vblank */
+@@ -1751,6 +1900,10 @@ bool dcn20_validate_bandwidth(struct dc *dc,
+ hsplit_pipe->stream = NULL;
+ hsplit_pipe->top_pipe = NULL;
+ hsplit_pipe->bottom_pipe = NULL;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ if (hsplit_pipe->stream_res.dsc && hsplit_pipe->stream_res.dsc != pipe->stream_res.dsc)
++ release_dsc(&context->res_ctx, dc->res_pool, hsplit_pipe->stream_res.dsc);
++#endif
+ /* Clear plane_res and stream_res */
+ memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res));
+ memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res));
+@@ -1997,6 +2150,10 @@ bool dcn20_validate_bandwidth(struct dc *dc,
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz =
+ pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ context->res_ctx.pipe_ctx[i].plane_res.bw.dscclk_khz =
++ context->bw_ctx.dml.vba.DSCCLK_calculated[pipe_idx] * 1000;
++#endif
+ context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+ pipe_idx++;
+ }
+@@ -2045,6 +2202,23 @@ enum dc_status dcn20_validate_global(struct dc *dc, struct dc_state *new_ctx)
+ if (pipe_ctx->stream != stream)
+ continue;
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ if (stream->timing.flags.DSC) {
++ if (pipe_ctx->stream_res.dsc != NULL) {
++ struct dsc_config dsc_cfg;
++
++ 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;
++
++ if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg))
++ result = DC_FAIL_DSC_VALIDATE;
++ } else
++ result = DC_FAIL_DSC_VALIDATE; // DSC enabled for this stream, but no free DSCs available
++ }
++#endif
+ }
+ }
+
+@@ -2715,6 +2889,16 @@ static bool construct(
+ goto create_fail;
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
++ pool->base.dscs[i] = dcn20_dsc_create(ctx, i);
++ if (pool->base.dscs[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dm_error("DC: failed to create display stream compressor %d!\n", i);
++ goto create_fail;
++ }
++ }
++#endif
+
+ if (!resource_construct(num_virtual_links, dc, &pool->base,
+ (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ?
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
+index c38c85c8e3b9..d99b1fc8f2df 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
+@@ -203,7 +203,165 @@ static void enc2_stream_encoder_stop_hdmi_info_packets(
+ HDMI_GENERIC7_LINE, 0);
+ }
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++struct dc_info_packet_128 {
++ bool valid;
++ uint8_t hb0;
++ uint8_t hb1;
++ uint8_t hb2;
++ uint8_t hb3;
++ uint8_t sb[128];
++};
++
++/* Update GSP7 SDP 128 byte long */
++static void enc2_send_gsp7_128_info_packet(
++ struct dcn10_stream_encoder *enc1,
++ const struct dc_info_packet_128 *info_packet)
++{
++ uint32_t i;
++
++ /* TODOFPGA Figure out a proper number for max_retries polling for lock
++ * use 50 for now.
++ */
++ uint32_t max_retries = 50;
++ const uint32_t *content = (const uint32_t *) &info_packet->sb[0];
++
++ ASSERT(info_packet->hb1 == DC_DP_INFOFRAME_TYPE_PPS);
++
++ /* Configure for PPS packet size (128 bytes) */
++ REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP7_PPS, 1);
++
++ /* We need turn on clock before programming AFMT block*/
++ REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
++
++ /* Poll dig_update_lock is not locked -> asic internal signal
++ * assumes otg master lock will unlock it
++ */
++ /*REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_LOCK_STATUS, 0, 10, max_retries);*/
+
++ /* Wait for HW/SW GSP memory access conflict to go away */
++ REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT,
++ 0, 10, max_retries);
++
++ /* Clear HW/SW memory access conflict flag */
++ REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT_CLR, 1);
++
++ /* write generic packet header */
++ REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_INDEX, 7);
++ REG_SET_4(AFMT_GENERIC_HDR, 0,
++ AFMT_GENERIC_HB0, info_packet->hb0,
++ AFMT_GENERIC_HB1, info_packet->hb1,
++ AFMT_GENERIC_HB2, info_packet->hb2,
++ AFMT_GENERIC_HB3, info_packet->hb3);
++
++ /* Write generic packet content 128 bytes long. Four sets are used (indexes 7
++ * through 10) to fit 128 bytes.
++ */
++ for (i = 0; i < 4; i++) {
++ uint32_t packet_index = 7 + i;
++ REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_INDEX, packet_index);
++
++ REG_WRITE(AFMT_GENERIC_0, *content++);
++ REG_WRITE(AFMT_GENERIC_1, *content++);
++ REG_WRITE(AFMT_GENERIC_2, *content++);
++ REG_WRITE(AFMT_GENERIC_3, *content++);
++ REG_WRITE(AFMT_GENERIC_4, *content++);
++ REG_WRITE(AFMT_GENERIC_5, *content++);
++ REG_WRITE(AFMT_GENERIC_6, *content++);
++ REG_WRITE(AFMT_GENERIC_7, *content++);
++ }
++
++ REG_UPDATE(AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE, 1);
++}
++
++/* Set DSC-related configuration.
++ * dsc_mode: 0 disables DSC, other values enable DSC in specified format
++ * sc_bytes_per_pixel: Bytes per pixel in u3.28 format
++ * dsc_slice_width: Slice width in pixels
++ */
++static void enc2_dp_set_dsc_config(struct stream_encoder *enc,
++ enum optc_dsc_mode dsc_mode,
++ uint32_t dsc_bytes_per_pixel,
++ uint32_t dsc_slice_width,
++ uint8_t *dsc_packed_pps)
++{
++ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
++
++ REG_UPDATE_2(DP_DSC_CNTL,
++ DP_DSC_MODE, dsc_mode,
++ DP_DSC_SLICE_WIDTH, dsc_slice_width);
++
++ REG_SET(DP_DSC_BYTES_PER_PIXEL, 0,
++ DP_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel);
++
++ if (dsc_mode != OPTC_DSC_DISABLED) {
++ struct dc_info_packet_128 pps_sdp;
++
++ ASSERT(dsc_packed_pps);
++
++ /* Load PPS into infoframe (SDP) registers */
++ pps_sdp.valid = true;
++ pps_sdp.hb0 = 0;
++ pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS;
++ pps_sdp.hb2 = 127;
++ pps_sdp.hb3 = 0;
++ memcpy(&pps_sdp.sb[0], dsc_packed_pps, sizeof(pps_sdp.sb));
++ enc2_send_gsp7_128_info_packet(enc1, &pps_sdp);
++
++ /* Enable Generic Stream Packet 7 (GSP) transmission */
++ //REG_UPDATE(DP_SEC_CNTL,
++ // DP_SEC_GSP7_ENABLE, 1);
++
++ /* SW should make sure VBID[6] update line number is bigger
++ * than PPS transmit line number
++ */
++ REG_UPDATE(DP_SEC_CNTL6,
++ DP_SEC_GSP7_LINE_NUM, 2);
++ REG_UPDATE_2(DP_MSA_VBID_MISC,
++ DP_VBID6_LINE_REFERENCE, 0,
++ DP_VBID6_LINE_NUM, 3);
++
++ /* Send PPS data at the line number specified above.
++ * DP spec requires PPS to be sent only when it changes, however since
++ * decoder has to be able to handle its change on every frame, we're
++ * sending it always (i.e. on every frame) to reduce the chance it'd be
++ * missed by decoder. If it turns out required to send PPS only when it
++ * changes, we can use DP_SEC_GSP7_SEND register.
++ */
++ REG_UPDATE_2(DP_SEC_CNTL,
++ DP_SEC_GSP7_ENABLE, 1,
++ DP_SEC_STREAM_ENABLE, 1);
++ } else {
++ /* Disable Generic Stream Packet 7 (GSP) transmission */
++ REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, 0);
++ REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP7_PPS, 0);
++ }
++}
++#endif
++
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++/* this function read dsc related register fields to be logged later in dcn10_log_hw_state
++ * into a dcn_dsc_state struct.
++ */
++static void enc2_read_state(struct stream_encoder *enc, struct enc_state *s)
++{
++ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
++
++ //if dsc is enabled, continue to read
++ REG_GET(DP_DSC_CNTL, DP_DSC_MODE, &s->dsc_mode);
++ if (s->dsc_mode) {
++ REG_GET(DP_DSC_CNTL, DP_DSC_SLICE_WIDTH, &s->dsc_slice_width);
++ REG_GET(DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, &s->sec_gsp7_line_num);
++
++ REG_GET(DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, &s->sec_gsp7_line_num);
++ REG_GET(DP_MSA_VBID_MISC, DP_VBID6_LINE_REFERENCE, &s->vbid6_line_reference);
++ REG_GET(DP_MSA_VBID_MISC, DP_VBID6_LINE_NUM, &s->vbid6_line_num);
++
++ REG_GET(DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, &s->sec_gsp7_enable);
++ REG_GET(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, &s->sec_stream_enable);
++ }
++}
++#endif
+
+ /* Set Dynamic Metadata-configuration.
+ * enable_dme: TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME
+@@ -283,6 +441,10 @@ static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
+ {
+ bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
++ && !timing->dsc_cfg.ycbcr422_simple);
++#endif
+ return two_pix;
+ }
+
+@@ -416,7 +578,13 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
+ .setup_stereo_sync = enc1_setup_stereo_sync,
+ .set_avmute = enc1_stream_encoder_set_avmute,
+ .dig_connect_to_otg = enc1_dig_connect_to_otg,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .enc_read_state = enc2_read_state,
++#endif
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .dp_set_dsc_config = enc2_dp_set_dsc_config,
++#endif
+ .set_dynamic_metadata = enc2_set_dynamic_metadata,
+ };
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+index ccbfe9680d27..b6b4333737f2 100644
+--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
++++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+@@ -118,6 +118,13 @@ bool dm_helpers_submit_i2c(
+ const struct dc_link *link,
+ struct i2c_command *cmd);
+
++#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
++);
++#endif
+ bool dm_helpers_is_dp_sink_present(
+ struct dc_link *link);
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile
+new file mode 100644
+index 000000000000..c5d5b94e2604
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile
+@@ -0,0 +1,13 @@
++#
++# Makefile for the 'dsc' sub-component of DAL.
++
++CFLAGS_rc_calc.o := -mhard-float -msse -mpreferred-stack-boundary=4
++CFLAGS_rc_calc_dpi.o := -mhard-float -msse -mpreferred-stack-boundary=4
++CFLAGS_codec_main_amd.o := -mhard-float -msse -mpreferred-stack-boundary=4
++CFLAGS_dc_dsc.o := -mhard-float -msse -mpreferred-stack-boundary=4
++
++DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o
++
++AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC))
++
++AMD_DISPLAY_FILES += $(AMD_DAL_DSC)
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
+new file mode 100644
+index 000000000000..4ffcc2844d19
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
+@@ -0,0 +1,899 @@
++/*
++ * Copyright 2019 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Author: AMD
++ */
++
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#include "dc.h"
++#include "core_types.h"
++#include "dsc.h"
++#include <drm/drm_dp_helper.h>
++
++/* This module's internal functions */
++
++static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int *buff_block_size)
++{
++
++ switch (dpcd_buff_block_size) {
++ case DP_DSC_RC_BUF_BLK_SIZE_1:
++ *buff_block_size = 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_4:
++ *buff_block_size = 4 * 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_16:
++ *buff_block_size = 16 * 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_64:
++ *buff_block_size = 64 * 1024;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC buffer size not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++
++static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *line_buff_bit_depth)
++{
++ if (0 <= dpcd_line_buff_bit_depth && dpcd_line_buff_bit_depth <= 7)
++ *line_buff_bit_depth = dpcd_line_buff_bit_depth + 9;
++ else if (dpcd_line_buff_bit_depth == 8)
++ *line_buff_bit_depth = 8;
++ else {
++ dm_error("%s: DPCD DSC buffer depth not recoginzed.\n", __func__);
++ return false;
++ }
++
++ return true;
++}
++
++
++static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput)
++{
++ switch (dpcd_throughput) {
++ case DP_DSC_THROUGHPUT_MODE_0_340:
++ *throughput = 340;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_400:
++ *throughput = 400;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_450:
++ *throughput = 450;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_500:
++ *throughput = 500;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_550:
++ *throughput = 550;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_600:
++ *throughput = 600;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_650:
++ *throughput = 650;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_700:
++ *throughput = 700;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_750:
++ *throughput = 750;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_800:
++ *throughput = 800;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_850:
++ *throughput = 850;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_900:
++ *throughput = 900;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_950:
++ *throughput = 950;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_1000:
++ *throughput = 1000;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC througput mode not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++
++static bool dsc_bpp_increment_div_from_dpcd(int bpp_increment_dpcd, uint32_t *bpp_increment_div)
++{
++
++ switch (bpp_increment_dpcd) {
++ case 0:
++ *bpp_increment_div = 16;
++ break;
++ case 1:
++ *bpp_increment_div = 8;
++ break;
++ case 2:
++ *bpp_increment_div = 4;
++ break;
++ case 3:
++ *bpp_increment_div = 2;
++ break;
++ case 4:
++ *bpp_increment_div = 1;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC bits-per-pixel increment not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++static void get_dsc_enc_caps(
++ const struct dc *dc,
++ struct dsc_enc_caps *dsc_enc_caps,
++ int pixel_clock_100Hz)
++{
++ // This is a static HW query, so we can use any DSC
++ struct display_stream_compressor *dsc = dc->res_pool->dscs[0];
++
++ memset(dsc_enc_caps, 0, sizeof(struct dsc_enc_caps));
++ if (dsc)
++ dsc->funcs->dsc_get_enc_caps(dsc_enc_caps, pixel_clock_100Hz);
++}
++
++/* Returns 'false' if no intersection was found for at least one capablity.
++ * It also implicitly validates some sink caps against invalid value of zero.
++ */
++static bool dc_intersect_dsc_caps(
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ const struct dsc_enc_caps *dsc_enc_caps,
++ enum dc_pixel_encoding pixel_encoding,
++ struct dsc_enc_caps *dsc_common_caps)
++{
++ int32_t max_slices;
++ int32_t total_sink_throughput;
++
++ memset(dsc_common_caps, 0, sizeof(struct dsc_enc_caps));
++
++ dsc_common_caps->dsc_version = min(dsc_sink_caps->dsc_version, dsc_enc_caps->dsc_version);
++ if (!dsc_common_caps->dsc_version)
++ return false;
++
++ dsc_common_caps->slice_caps.bits.NUM_SLICES_1 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_1;
++ dsc_common_caps->slice_caps.bits.NUM_SLICES_2 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_2;
++ dsc_common_caps->slice_caps.bits.NUM_SLICES_4 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_4;
++ dsc_common_caps->slice_caps.bits.NUM_SLICES_8 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_8;
++ if (!dsc_common_caps->slice_caps.raw)
++ return false;
++
++ dsc_common_caps->lb_bit_depth = min(dsc_sink_caps->lb_bit_depth, dsc_enc_caps->lb_bit_depth);
++ if (!dsc_common_caps->lb_bit_depth)
++ return false;
++
++ dsc_common_caps->is_block_pred_supported = dsc_sink_caps->is_block_pred_supported && dsc_enc_caps->is_block_pred_supported;
++
++ dsc_common_caps->color_formats.raw = dsc_sink_caps->color_formats.raw & dsc_enc_caps->color_formats.raw;
++ if (!dsc_common_caps->color_formats.raw)
++ return false;
++
++ dsc_common_caps->color_depth.raw = dsc_sink_caps->color_depth.raw & dsc_enc_caps->color_depth.raw;
++ if (!dsc_common_caps->color_depth.raw)
++ return false;
++
++ max_slices = 0;
++ if (dsc_common_caps->slice_caps.bits.NUM_SLICES_1)
++ max_slices = 1;
++
++ if (dsc_common_caps->slice_caps.bits.NUM_SLICES_2)
++ max_slices = 2;
++
++ if (dsc_common_caps->slice_caps.bits.NUM_SLICES_4)
++ max_slices = 4;
++
++ total_sink_throughput = max_slices * dsc_sink_caps->throughput_mode_0_mps;
++ if (pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420)
++ total_sink_throughput = max_slices * dsc_sink_caps->throughput_mode_1_mps;
++
++ dsc_common_caps->max_total_throughput_mps = min(total_sink_throughput, dsc_enc_caps->max_total_throughput_mps);
++
++ dsc_common_caps->max_slice_width = min(dsc_sink_caps->max_slice_width, dsc_enc_caps->max_slice_width);
++ if (!dsc_common_caps->max_slice_width)
++ return false;
++
++ dsc_common_caps->bpp_increment_div = min(dsc_sink_caps->bpp_increment_div, dsc_enc_caps->bpp_increment_div);
++
++ return true;
++}
++
++// TODO DSC: Can this be moved to a common helper module and replace WindowsDM::calcRequiredBandwidthForTiming()?
++static int bpp_from_dc_color_depth(enum dc_color_depth color_depth)
++{
++ int bits_per_pixel;
++
++ // Get color depth in bits per pixel
++ switch (color_depth) {
++ case COLOR_DEPTH_UNDEFINED:
++ bits_per_pixel = 0;
++ break;
++ case COLOR_DEPTH_666:
++ bits_per_pixel = 6;
++ break;
++ case COLOR_DEPTH_888:
++ bits_per_pixel = 8;
++ break;
++ case COLOR_DEPTH_101010:
++ bits_per_pixel = 10;
++ break;
++ case COLOR_DEPTH_121212:
++ bits_per_pixel = 12;
++ break;
++ case COLOR_DEPTH_141414:
++ bits_per_pixel = 14;
++ break;
++ case COLOR_DEPTH_161616:
++ bits_per_pixel = 16;
++ break;
++ case COLOR_DEPTH_999:
++ bits_per_pixel = 9;
++ break;
++ case COLOR_DEPTH_111111:
++ bits_per_pixel = 11;
++ break;
++ case COLOR_DEPTH_COUNT:
++ default:
++ bits_per_pixel = 0;
++ break;
++ }
++
++ return bits_per_pixel;
++}
++
++// TODO DSC: Can this be moved to a common helper module and replace WindowsDM::calcRequiredBandwidthForTiming()?
++static int calc_required_bandwidth_for_timing(const struct dc_crtc_timing *crtc_timing)
++{
++ int timing_bandwidth_kbps = 0;
++ int bits_per_pixel = bpp_from_dc_color_depth(crtc_timing->display_color_depth);
++
++ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB ||
++ crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
++ timing_bandwidth_kbps = crtc_timing->pix_clk_100hz * bits_per_pixel * 3 / 10;
++ else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
++ timing_bandwidth_kbps = crtc_timing->pix_clk_100hz * 8 * 3 / 10;
++ else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
++ timing_bandwidth_kbps = crtc_timing->pix_clk_100hz * bits_per_pixel * 3 / 20;
++
++ return timing_bandwidth_kbps;
++}
++
++struct dc_dsc_policy {
++ float max_compression_ratio_legacy;
++ float sst_compression_legacy; // Maximum quality if 0.0
++ float mst_compression_legacy;
++ bool use_min_slices_h;
++ int max_slices_h; // Maximum available if 0
++ int num_slices_v;
++ int max_target_bpp;
++ int min_target_bpp; // Minimum target bits per pixel
++};
++
++static inline uint32_t dsc_round_up(uint32_t value)
++{
++ return (value + 9) / 10;
++}
++
++static inline uint32_t calc_dsc_bpp_x16(uint32_t stream_bandwidth_kbps, uint32_t pix_clk_100hz, uint32_t bpp_increment_div)
++{
++ uint32_t dsc_target_bpp_x16;
++ float f_dsc_target_bpp;
++ float f_stream_bandwidth_100bps = stream_bandwidth_kbps * 10.0f;
++ uint32_t precision = bpp_increment_div; // bpp_increment_div is actually precision
++
++ f_dsc_target_bpp = f_stream_bandwidth_100bps / pix_clk_100hz;
++
++ // Round down to the nearest precision stop to bring it into DSC spec range
++ dsc_target_bpp_x16 = (uint32_t)(f_dsc_target_bpp * precision);
++ dsc_target_bpp_x16 = (dsc_target_bpp_x16 * 16) / precision;
++
++ return dsc_target_bpp_x16;
++}
++
++const struct dc_dsc_policy dsc_policy = {
++ .max_compression_ratio_legacy = 3.0f, // DSC Policy: Limit compression to 3:1 at most in all cases
++ .sst_compression_legacy = 0.0f, // DSC Policy: SST - Maximum quality (0.0)
++ .mst_compression_legacy = 3.0f, // DSC Policy: MST - always 3:1 compression
++ .use_min_slices_h = true, // DSC Policy: Use minimum number of slices that fits the pixel clock
++ .max_slices_h = 0, // DSC Policy: Use max available slices (in our case 4 for or 8, depending on the mode)
++
++ /* DSC Policy: Number of vertical slices set to 2 for no particular reason.
++ * Seems small enough to not affect the quality too much, while still providing some error
++ * propagation control (which may also help debugging).
++ */
++ .num_slices_v = 16,
++ .max_target_bpp = 24,
++ .min_target_bpp = 8,
++};
++
++static void get_dsc_bandwidth_range(
++ const struct dc_dsc_policy *policy,
++ const struct dsc_enc_caps *dsc_caps,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_bw_range *range)
++{
++ /* native stream bandwidth */
++ range->stream_kbps = calc_required_bandwidth_for_timing(timing);
++
++ /* max dsc target bpp */
++ range->max_kbps = dsc_round_up(policy->max_target_bpp * timing->pix_clk_100hz);
++ range->max_target_bpp_x16 = policy->max_target_bpp * 16;
++ if (range->max_kbps > range->stream_kbps) {
++ /* max dsc target bpp is capped to native bandwidth */
++ range->max_kbps = range->stream_kbps;
++ range->max_target_bpp_x16 = calc_dsc_bpp_x16(range->stream_kbps, timing->pix_clk_100hz, dsc_caps->bpp_increment_div);
++ }
++
++ /* min dsc target bpp */
++ range->min_kbps = dsc_round_up(policy->min_target_bpp * timing->pix_clk_100hz);
++ range->min_target_bpp_x16 = policy->min_target_bpp * 16;
++ if (range->min_kbps > range->max_kbps) {
++ /* min dsc target bpp is capped to max dsc bandwidth*/
++ range->min_kbps = range->max_kbps;
++ range->min_target_bpp_x16 = range->max_target_bpp_x16;
++ }
++}
++
++static bool decide_dsc_target_bpp_x16(
++ const struct dc_dsc_policy *policy,
++ const struct dsc_enc_caps *dsc_common_caps,
++ const int target_bandwidth,
++ const struct dc_crtc_timing *timing,
++ int *target_bpp_x16)
++{
++ bool should_use_dsc = false;
++ struct dc_dsc_bw_range range;
++ float target_bandwidth_kbps = target_bandwidth * 0.97f; // 3% overhead for FEC
++
++ memset(&range, 0, sizeof(range));
++
++ get_dsc_bandwidth_range(policy, dsc_common_caps, timing, &range);
++ if (target_bandwidth_kbps >= range.stream_kbps) {
++ /* enough bandwidth without dsc */
++ *target_bpp_x16 = 0;
++ should_use_dsc = false;
++ } else if (target_bandwidth_kbps >= range.max_kbps) {
++ /* use max target bpp allowed */
++ *target_bpp_x16 = range.max_target_bpp_x16;
++ should_use_dsc = true;
++ } else if (target_bandwidth_kbps >= range.min_kbps) {
++ /* use target bpp that can take entire target bandwidth */
++ *target_bpp_x16 = calc_dsc_bpp_x16(target_bandwidth_kbps, timing->pix_clk_100hz, dsc_common_caps->bpp_increment_div);
++ should_use_dsc = true;
++ } else {
++ /* not enough bandwidth to fulfill minimum requirement */
++ *target_bpp_x16 = 0;
++ should_use_dsc = false;
++ }
++
++ return should_use_dsc;
++}
++
++
++#define MIN_AVAILABLE_SLICES_SIZE 4
++
++static int get_available_dsc_slices(union dsc_enc_slice_caps slice_caps, int *available_slices)
++{
++ int idx = 0;
++
++ memset(available_slices, -1, MIN_AVAILABLE_SLICES_SIZE);
++
++ if (slice_caps.bits.NUM_SLICES_1)
++ available_slices[idx++] = 1;
++
++ if (slice_caps.bits.NUM_SLICES_2)
++ available_slices[idx++] = 2;
++
++ if (slice_caps.bits.NUM_SLICES_4)
++ available_slices[idx++] = 4;
++
++ if (slice_caps.bits.NUM_SLICES_8)
++ available_slices[idx++] = 8;
++
++ return idx;
++}
++
++
++static int get_max_dsc_slices(union dsc_enc_slice_caps slice_caps)
++{
++ int max_slices = 0;
++ int available_slices[MIN_AVAILABLE_SLICES_SIZE];
++ int end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]);
++
++ if (end_idx > 0)
++ max_slices = available_slices[end_idx - 1];
++
++ return max_slices;
++}
++
++
++// Increment sice number in available sice numbers stops if possible, or just increment if not
++static int inc_num_slices(union dsc_enc_slice_caps slice_caps, int num_slices)
++{
++ // Get next bigger num slices available in common caps
++ int available_slices[MIN_AVAILABLE_SLICES_SIZE];
++ int end_idx;
++ int i;
++ int new_num_slices = num_slices;
++
++ end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]);
++ if (end_idx == 0) {
++ // No available slices found
++ new_num_slices++;
++ return new_num_slices;
++ }
++
++ // Numbers of slices found - get the next bigger number
++ for (i = 0; i < end_idx; i++) {
++ if (new_num_slices < available_slices[i]) {
++ new_num_slices = available_slices[i];
++ break;
++ }
++ }
++
++ if (new_num_slices == num_slices) // No biger number of slices found
++ new_num_slices++;
++
++ return new_num_slices;
++}
++
++
++// Decrement sice number in available sice numbers stops if possible, or just decrement if not. Stop at zero.
++static int dec_num_slices(union dsc_enc_slice_caps slice_caps, int num_slices)
++{
++ // Get next bigger num slices available in common caps
++ int available_slices[MIN_AVAILABLE_SLICES_SIZE];
++ int end_idx;
++ int i;
++ int new_num_slices = num_slices;
++
++ end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]);
++ if (end_idx == 0 && new_num_slices > 0) {
++ // No numbers of slices found
++ new_num_slices++;
++ return new_num_slices;
++ }
++
++ // Numbers of slices found - get the next smaller number
++ for (i = end_idx - 1; i >= 0; i--) {
++ if (new_num_slices > available_slices[i]) {
++ new_num_slices = available_slices[i];
++ break;
++ }
++ }
++
++ if (new_num_slices == num_slices) {
++ // No smaller number of slices found
++ new_num_slices--;
++ if (new_num_slices < 0)
++ new_num_slices = 0;
++ }
++
++ return new_num_slices;
++}
++
++
++// Choose next bigger number of slices if the requested number of slices is not available
++static int fit_num_slices_up(union dsc_enc_slice_caps slice_caps, int num_slices)
++{
++ // Get next bigger num slices available in common caps
++ int available_slices[MIN_AVAILABLE_SLICES_SIZE];
++ int end_idx;
++ int i;
++ int new_num_slices = num_slices;
++
++ end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]);
++ if (end_idx == 0) {
++ // No available slices found
++ new_num_slices++;
++ return new_num_slices;
++ }
++
++ // Numbers of slices found - get the equal or next bigger number
++ for (i = 0; i < end_idx; i++) {
++ if (new_num_slices <= available_slices[i]) {
++ new_num_slices = available_slices[i];
++ break;
++ }
++ }
++
++ return new_num_slices;
++}
++
++
++/* Attempts to set DSC configuration for the stream, applying DSC policy.
++ * Returns 'true' if successful or 'false' if not.
++ *
++ * Parameters:
++ *
++ * dsc_sink_caps - DSC sink decoder capabilities (from DPCD)
++ *
++ * dsc_enc_caps - DSC encoder capabilities
++ *
++ * target_bandwidth - Target bandwidth to fit the stream into.
++ * If 0, use maximum compression as per DSC policy.
++ *
++ * timing - The stream timing to fit into 'target_bandwidth' or apply
++ * maximum compression to, if 'target_badwidth == 0'
++ *
++ * dsc_cfg - DSC configuration to use if it was possible to come up with
++ * one for the given inputs.
++ * The target bitrate after DSC can be calculated by multiplying
++ * dsc_cfg.bits_per_pixel (in U6.4 format) by pixel rate, e.g.
++ *
++ * dsc_stream_bitrate_kbps = (int)ceil(timing->pix_clk_khz * dsc_cfg.bits_per_pixel / 16.0);
++ */
++static bool setup_dsc_config(
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ const struct dsc_enc_caps *dsc_enc_caps,
++ int target_bandwidth,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_config *dsc_cfg)
++{
++ struct dsc_enc_caps dsc_common_caps;
++ int max_slices_h;
++ int min_slices_h;
++ int num_slices_h;
++ int pic_width;
++ int slice_width;
++ int target_bpp;
++ int sink_per_slice_throughput;
++ // TODO DSC: See if it makes sense to use 2.4% for SST
++ bool is_dsc_possible = false;
++ int num_slices_v;
++ int pic_height;
++
++ memset(dsc_cfg, 0, sizeof(struct dc_dsc_config));
++
++ if (!dsc_sink_caps->is_dsc_supported)
++ goto done;
++
++ // Intersect decoder with encoder DSC caps and validate DSC settings
++ is_dsc_possible = dc_intersect_dsc_caps(dsc_sink_caps, dsc_enc_caps, timing->pixel_encoding, &dsc_common_caps);
++ if (!is_dsc_possible)
++ goto done;
++
++ if (target_bandwidth > 0) {
++ is_dsc_possible = decide_dsc_target_bpp_x16(&dsc_policy, &dsc_common_caps, target_bandwidth, timing, &target_bpp);
++ } else if (timing->pix_clk_100hz * 12 <= calc_required_bandwidth_for_timing(timing) * 10) {
++ /* use 12 target bpp for MST display
++ * TODO: implement new MST DSC target bpp policy */
++ target_bpp = 16*12;
++ is_dsc_possible = true;
++ } else {
++ is_dsc_possible = false;
++ }
++
++ if (!is_dsc_possible)
++ goto done;
++
++ dsc_cfg->bits_per_pixel = target_bpp;
++
++ sink_per_slice_throughput = 0;
++
++ // Validate available DSC settings against the mode timing
++
++ // Color format
++ dsc_cfg->ycbcr422_simple = false;
++ switch (timing->pixel_encoding) {
++ case PIXEL_ENCODING_RGB:
++ is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.RGB;
++ sink_per_slice_throughput = dsc_sink_caps->throughput_mode_0_mps;
++ break;
++ case PIXEL_ENCODING_YCBCR444:
++ is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_444;
++ sink_per_slice_throughput = dsc_sink_caps->throughput_mode_0_mps;
++ break;
++ case PIXEL_ENCODING_YCBCR422: {
++ is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_422;
++ sink_per_slice_throughput = dsc_sink_caps->throughput_mode_1_mps;
++ if (!is_dsc_possible) {
++ is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_SIMPLE_422;
++ dsc_cfg->ycbcr422_simple = is_dsc_possible;
++ sink_per_slice_throughput = dsc_sink_caps->throughput_mode_0_mps;
++ }
++ }
++ break;
++ case PIXEL_ENCODING_YCBCR420:
++ is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_420;
++ sink_per_slice_throughput = dsc_sink_caps->throughput_mode_1_mps;
++ break;
++ default:
++ is_dsc_possible = false;
++ }
++
++ if (!is_dsc_possible)
++ goto done;
++
++ // Color depth
++ switch (timing->display_color_depth) {
++ case COLOR_DEPTH_888:
++ is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_8_BPC;
++ break;
++ case COLOR_DEPTH_101010:
++ is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_10_BPC;
++ break;
++ case COLOR_DEPTH_121212:
++ is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_12_BPC;
++ break;
++ default:
++ is_dsc_possible = false;
++ }
++
++ if (!is_dsc_possible)
++ goto done;
++
++ // DSC slicing
++ max_slices_h = get_max_dsc_slices(dsc_common_caps.slice_caps);
++
++ pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right;
++ while (max_slices_h > 0) {
++ if (pic_width % max_slices_h == 0)
++ break;
++
++ max_slices_h = dec_num_slices(dsc_common_caps.slice_caps, max_slices_h);
++ }
++
++ is_dsc_possible = (dsc_common_caps.max_slice_width > 0);
++ if (!is_dsc_possible)
++ goto done;
++
++ min_slices_h = pic_width / dsc_common_caps.max_slice_width;
++ if (pic_width % dsc_common_caps.max_slice_width)
++ min_slices_h++;
++
++ min_slices_h = fit_num_slices_up(dsc_common_caps.slice_caps, min_slices_h);
++
++ while (min_slices_h <= max_slices_h) {
++ if (dsc_round_up(timing->pix_clk_100hz) / (min_slices_h) <= sink_per_slice_throughput * 1000)
++ break;
++
++ min_slices_h = inc_num_slices(dsc_common_caps.slice_caps, min_slices_h);
++ }
++
++ if (pic_width % min_slices_h != 0)
++ min_slices_h = 0; // DSC TODO: Maybe try increasing the number of slices first?
++
++ is_dsc_possible = (min_slices_h <= max_slices_h);
++ if (!is_dsc_possible)
++ goto done;
++
++ if (dsc_policy.use_min_slices_h) {
++ if (min_slices_h > 0)
++ num_slices_h = min_slices_h;
++ else if (max_slices_h > 0) { // Fall back to max slices if min slices is not working out
++ if (dsc_policy.max_slices_h)
++ num_slices_h = min(dsc_policy.max_slices_h, max_slices_h);
++ else
++ num_slices_h = max_slices_h;
++ } else
++ is_dsc_possible = false;
++ } else {
++ if (max_slices_h > 0) {
++ if (dsc_policy.max_slices_h)
++ num_slices_h = min(dsc_policy.max_slices_h, max_slices_h);
++ else
++ num_slices_h = max_slices_h;
++ } else if (min_slices_h > 0) // Fall back to min slices if max slices is not possible
++ num_slices_h = min_slices_h;
++ else
++ is_dsc_possible = false;
++ }
++
++ if (!is_dsc_possible)
++ goto done;
++
++ dsc_cfg->num_slices_h = num_slices_h;
++ slice_width = pic_width / num_slices_h;
++
++ // Vertical number of slices: start from policy and pick the first one that height is divisible by
++ pic_height = timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
++ num_slices_v = dsc_policy.num_slices_v;
++ if (num_slices_v < 1)
++ num_slices_v = 1;
++
++ while (num_slices_v >= 1 && (pic_height % num_slices_v != 0))
++ num_slices_v--;
++
++ dsc_cfg->num_slices_v = num_slices_v;
++
++ is_dsc_possible = slice_width <= dsc_common_caps.max_slice_width;
++ if (!is_dsc_possible)
++ goto done;
++
++ // Final decission: can we do DSC or not?
++ if (is_dsc_possible) {
++ // Fill out the rest of DSC settings
++ dsc_cfg->block_pred_enable = dsc_common_caps.is_block_pred_supported;
++ dsc_cfg->linebuf_depth = dsc_common_caps.lb_bit_depth;
++ dsc_cfg->version_minor = (dsc_common_caps.dsc_version & 0xf0) >> 4;
++ }
++
++done:
++ if (!is_dsc_possible)
++ memset(dsc_cfg, 0, sizeof(struct dc_dsc_config));
++
++ return is_dsc_possible;
++}
++
++bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_data, struct dsc_dec_dpcd_caps *dsc_sink_caps)
++{
++ dsc_sink_caps->is_dsc_supported = (dpcd_dsc_data[DP_DSC_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_DECOMPRESSION_IS_SUPPORTED) != 0;
++ if (!dsc_sink_caps->is_dsc_supported)
++ return true;
++
++ dsc_sink_caps->dsc_version = dpcd_dsc_data[DP_DSC_REV - DP_DSC_SUPPORT];
++
++ {
++ int buff_block_size;
++ int buff_size;
++
++ if (!dsc_buff_block_size_from_dpcd(dpcd_dsc_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT], &buff_block_size))
++ return false;
++
++ buff_size = dpcd_dsc_data[DP_DSC_RC_BUF_SIZE - DP_DSC_SUPPORT] + 1;
++ dsc_sink_caps->rc_buffer_size = buff_size * buff_block_size;
++ }
++
++ dsc_sink_caps->slice_caps1.raw = dpcd_dsc_data[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT];
++ if (!dsc_line_buff_depth_from_dpcd(dpcd_dsc_data[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT], &dsc_sink_caps->lb_bit_depth))
++ return false;
++
++ dsc_sink_caps->is_block_pred_supported =
++ (dpcd_dsc_data[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_BLK_PREDICTION_IS_SUPPORTED) != 0;
++
++ dsc_sink_caps->edp_max_bits_per_pixel =
++ dpcd_dsc_data[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] |
++ dpcd_dsc_data[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] << 8;
++
++ dsc_sink_caps->color_formats.raw = dpcd_dsc_data[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT];
++ dsc_sink_caps->color_depth.raw = dpcd_dsc_data[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT];
++
++ {
++ int dpcd_throughput = dpcd_dsc_data[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT];
++
++ if (!dsc_throughput_from_dpcd(dpcd_throughput & DP_DSC_THROUGHPUT_MODE_0_MASK, &dsc_sink_caps->throughput_mode_0_mps))
++ return false;
++
++ dpcd_throughput = (dpcd_throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> DP_DSC_THROUGHPUT_MODE_1_SHIFT;
++ if (!dsc_throughput_from_dpcd(dpcd_throughput, &dsc_sink_caps->throughput_mode_1_mps))
++ return false;
++ }
++
++ dsc_sink_caps->max_slice_width = dpcd_dsc_data[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] * 320;
++ dsc_sink_caps->slice_caps2.raw = dpcd_dsc_data[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT];
++
++ if (!dsc_bpp_increment_div_from_dpcd(dpcd_dsc_data[DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT], &dsc_sink_caps->bpp_increment_div))
++ return false;
++
++ return true;
++}
++
++
++bool dc_dsc_compute_bandwidth_range(
++ const struct dc *dc,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_bw_range *range)
++{
++ bool is_dsc_possible = false;
++ struct dsc_enc_caps dsc_enc_caps;
++ struct dsc_enc_caps dsc_common_caps;
++ get_dsc_enc_caps(dc, &dsc_enc_caps, timing->pix_clk_100hz);
++ is_dsc_possible = dc_intersect_dsc_caps(dsc_sink_caps, &dsc_enc_caps, timing->pixel_encoding, &dsc_common_caps);
++ if (is_dsc_possible)
++ get_dsc_bandwidth_range(&dsc_policy, &dsc_common_caps, timing, range);
++ return is_dsc_possible;
++}
++
++bool dc_dsc_compute_config(
++ const struct dc *dc,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ int target_bandwidth,
++ const struct dc_crtc_timing *timing,
++ struct dc_dsc_config *dsc_cfg)
++{
++ bool is_dsc_possible = false;
++
++ struct dsc_enc_caps dsc_enc_caps;
++ struct dsc_enc_caps dsc_common_caps;
++
++ get_dsc_enc_caps(dc, &dsc_enc_caps, timing->pix_clk_100hz);
++ is_dsc_possible = dc_intersect_dsc_caps(dsc_sink_caps, &dsc_enc_caps,
++ timing->pixel_encoding, &dsc_common_caps);
++ if (is_dsc_possible)
++ is_dsc_possible = setup_dsc_config(dsc_sink_caps,
++ &dsc_enc_caps,
++ target_bandwidth,
++ timing, dsc_cfg);
++ return is_dsc_possible;
++}
++
++bool dc_check_and_fit_timing_into_bandwidth_with_dsc_legacy(
++ const struct dc *pDC,
++ const struct dc_link *link,
++ struct dc_crtc_timing *timing)
++{
++ int requiredBandwidth_Kbps;
++ bool stream_fits_into_bandwidth = false;
++ int link_rate_kbytes_per_sec = link->verified_link_cap.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
++ int total_link_bandwdith_kbps = link->verified_link_cap.lane_count * link_rate_kbytes_per_sec * 8;
++
++ if (link->preferred_link_setting.lane_count !=
++ LANE_COUNT_UNKNOWN &&
++ link->preferred_link_setting.link_rate !=
++ LINK_RATE_UNKNOWN) {
++ link_rate_kbytes_per_sec = link->preferred_link_setting.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
++ total_link_bandwdith_kbps = link->preferred_link_setting.lane_count * link_rate_kbytes_per_sec * 8;
++ }
++
++ timing->flags.DSC = 0;
++ requiredBandwidth_Kbps = calc_required_bandwidth_for_timing(timing);
++
++ if (total_link_bandwdith_kbps >= requiredBandwidth_Kbps)
++ stream_fits_into_bandwidth = true;
++ else {
++ // There's not enough bandwidth in the link. See if DSC can be used to resolve this.
++ int link_bandwidth_kbps = link->type == dc_connection_mst_branch ? 0 : total_link_bandwdith_kbps;
++
++ stream_fits_into_bandwidth = dc_setup_dsc_in_timing_legacy(pDC, &link->dpcd_caps.dsc_sink_caps, link_bandwidth_kbps, timing);
++ }
++
++ return stream_fits_into_bandwidth;
++}
++
++bool dc_setup_dsc_in_timing_legacy(const struct dc *pDC,
++ const struct dsc_dec_dpcd_caps *dsc_sink_caps,
++ int available_bandwidth_kbps,
++ struct dc_crtc_timing *timing)
++{
++ bool isDscOK = false;
++ struct dsc_enc_caps dsc_enc_caps;
++
++ timing->flags.DSC = 0;
++ get_dsc_enc_caps(pDC, &dsc_enc_caps, timing->pix_clk_100hz);
++ if (dsc_enc_caps.dsc_version) {
++ struct dc_dsc_config dscCfg = {0};
++
++ isDscOK = setup_dsc_config(dsc_sink_caps, &dsc_enc_caps, available_bandwidth_kbps, timing, &dscCfg);
++
++ memcpy(&timing->dsc_cfg, &dscCfg, sizeof(dscCfg));
++ timing->flags.DSC = isDscOK ? 1 : 0;
++ }
++
++ return isDscOK;
++}
++#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c b/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c
+new file mode 100644
+index 000000000000..67089765780b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c
+@@ -0,0 +1,382 @@
++// SPDX-License-Identifier: MIT
++/*
++ * Copyright © 2018 Intel Corp
++ *
++ * Author:
++ * Manasi Navare <manasi.d.navare@intel.com>
++ */
++
++/* DC versions of linux includes */
++#include <include/drm_dsc_dc.h>
++
++#define EXPORT_SYMBOL(symbol) /* nothing */
++#define BUILD_BUG_ON(cond) /* nothing */
++#define DIV_ROUND_UP(a, b) (((b) + (a) - 1) / (b))
++#define ERANGE -1
++#define DRM_DEBUG_KMS(msg) /* nothing */
++#define cpu_to_be16(__x) little_to_big(__x)
++
++static unsigned short little_to_big(int data)
++{
++ /* Swap lower and upper byte. DMCU uses big endian format. */
++ return (0xff & (data >> 8)) + ((data & 0xff) << 8);
++}
++
++/*
++ * Everything below this comment was copied directly from drm_dsc.c.
++ * Only the functions needed in DC are included.
++ * Please keep this file synced with upstream.
++ */
++
++/**
++ * DOC: dsc helpers
++ *
++ * These functions contain some common logic and helpers to deal with VESA
++ * Display Stream Compression standard required for DSC on Display Port/eDP or
++ * MIPI display interfaces.
++ */
++
++/**
++ * drm_dsc_pps_payload_pack() - Populates the DSC PPS
++ *
++ * @pps_payload:
++ * Bitwise struct for DSC Picture Parameter Set. This is defined
++ * by &struct drm_dsc_picture_parameter_set
++ * @dsc_cfg:
++ * DSC Configuration data filled by driver as defined by
++ * &struct drm_dsc_config
++ *
++ * DSC source device sends a picture parameter set (PPS) containing the
++ * information required by the sink to decode the compressed frame. Driver
++ * populates the DSC PPS struct using the DSC configuration parameters in
++ * the order expected by the DSC Display Sink device. For the DSC, the sink
++ * device expects the PPS payload in big endian format for fields
++ * that span more than 1 byte.
++ */
++void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_payload,
++ const struct drm_dsc_config *dsc_cfg)
++{
++ int i;
++
++ /* Protect against someone accidently changing struct size */
++ BUILD_BUG_ON(sizeof(*pps_payload) !=
++ DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1);
++
++ memset(pps_payload, 0, sizeof(*pps_payload));
++
++ /* PPS 0 */
++ pps_payload->dsc_version =
++ dsc_cfg->dsc_version_minor |
++ dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT;
++
++ /* PPS 1, 2 is 0 */
++
++ /* PPS 3 */
++ pps_payload->pps_3 =
++ dsc_cfg->line_buf_depth |
++ dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT;
++
++ /* PPS 4 */
++ pps_payload->pps_4 =
++ ((dsc_cfg->bits_per_pixel & DSC_PPS_BPP_HIGH_MASK) >>
++ DSC_PPS_MSB_SHIFT) |
++ dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT |
++ dsc_cfg->simple_422 << DSC_PPS_SIMPLE422_SHIFT |
++ dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT |
++ dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT;
++
++ /* PPS 5 */
++ pps_payload->bits_per_pixel_low =
++ (dsc_cfg->bits_per_pixel & DSC_PPS_LSB_MASK);
++
++ /*
++ * The DSC panel expects the PPS packet to have big endian format
++ * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert
++ * to big endian format. If format is little endian, it will swap
++ * bytes to convert to Big endian else keep it unchanged.
++ */
++
++ /* PPS 6, 7 */
++ pps_payload->pic_height = cpu_to_be16(dsc_cfg->pic_height);
++
++ /* PPS 8, 9 */
++ pps_payload->pic_width = cpu_to_be16(dsc_cfg->pic_width);
++
++ /* PPS 10, 11 */
++ pps_payload->slice_height = cpu_to_be16(dsc_cfg->slice_height);
++
++ /* PPS 12, 13 */
++ pps_payload->slice_width = cpu_to_be16(dsc_cfg->slice_width);
++
++ /* PPS 14, 15 */
++ pps_payload->chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size);
++
++ /* PPS 16 */
++ pps_payload->initial_xmit_delay_high =
++ ((dsc_cfg->initial_xmit_delay &
++ DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >>
++ DSC_PPS_MSB_SHIFT);
++
++ /* PPS 17 */
++ pps_payload->initial_xmit_delay_low =
++ (dsc_cfg->initial_xmit_delay & DSC_PPS_LSB_MASK);
++
++ /* PPS 18, 19 */
++ pps_payload->initial_dec_delay =
++ cpu_to_be16(dsc_cfg->initial_dec_delay);
++
++ /* PPS 20 is 0 */
++
++ /* PPS 21 */
++ pps_payload->initial_scale_value =
++ dsc_cfg->initial_scale_value;
++
++ /* PPS 22, 23 */
++ pps_payload->scale_increment_interval =
++ cpu_to_be16(dsc_cfg->scale_increment_interval);
++
++ /* PPS 24 */
++ pps_payload->scale_decrement_interval_high =
++ ((dsc_cfg->scale_decrement_interval &
++ DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >>
++ DSC_PPS_MSB_SHIFT);
++
++ /* PPS 25 */
++ pps_payload->scale_decrement_interval_low =
++ (dsc_cfg->scale_decrement_interval & DSC_PPS_LSB_MASK);
++
++ /* PPS 26[7:0], PPS 27[7:5] RESERVED */
++
++ /* PPS 27 */
++ pps_payload->first_line_bpg_offset =
++ dsc_cfg->first_line_bpg_offset;
++
++ /* PPS 28, 29 */
++ pps_payload->nfl_bpg_offset =
++ cpu_to_be16(dsc_cfg->nfl_bpg_offset);
++
++ /* PPS 30, 31 */
++ pps_payload->slice_bpg_offset =
++ cpu_to_be16(dsc_cfg->slice_bpg_offset);
++
++ /* PPS 32, 33 */
++ pps_payload->initial_offset =
++ cpu_to_be16(dsc_cfg->initial_offset);
++
++ /* PPS 34, 35 */
++ pps_payload->final_offset = cpu_to_be16(dsc_cfg->final_offset);
++
++ /* PPS 36 */
++ pps_payload->flatness_min_qp = dsc_cfg->flatness_min_qp;
++
++ /* PPS 37 */
++ pps_payload->flatness_max_qp = dsc_cfg->flatness_max_qp;
++
++ /* PPS 38, 39 */
++ pps_payload->rc_model_size =
++ cpu_to_be16(DSC_RC_MODEL_SIZE_CONST);
++
++ /* PPS 40 */
++ pps_payload->rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST;
++
++ /* PPS 41 */
++ pps_payload->rc_quant_incr_limit0 =
++ dsc_cfg->rc_quant_incr_limit0;
++
++ /* PPS 42 */
++ pps_payload->rc_quant_incr_limit1 =
++ dsc_cfg->rc_quant_incr_limit1;
++
++ /* PPS 43 */
++ pps_payload->rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST |
++ DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT;
++
++ /* PPS 44 - 57 */
++ for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
++ pps_payload->rc_buf_thresh[i] =
++ dsc_cfg->rc_buf_thresh[i];
++
++ /* PPS 58 - 87 */
++ /*
++ * For DSC sink programming the RC Range parameter fields
++ * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0]
++ */
++ for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
++ pps_payload->rc_range_parameters[i] =
++ ((dsc_cfg->rc_range_params[i].range_min_qp <<
++ DSC_PPS_RC_RANGE_MINQP_SHIFT) |
++ (dsc_cfg->rc_range_params[i].range_max_qp <<
++ DSC_PPS_RC_RANGE_MAXQP_SHIFT) |
++ (dsc_cfg->rc_range_params[i].range_bpg_offset));
++ pps_payload->rc_range_parameters[i] =
++ cpu_to_be16(pps_payload->rc_range_parameters[i]);
++ }
++
++ /* PPS 88 */
++ pps_payload->native_422_420 = dsc_cfg->native_422 |
++ dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT;
++
++ /* PPS 89 */
++ pps_payload->second_line_bpg_offset =
++ dsc_cfg->second_line_bpg_offset;
++
++ /* PPS 90, 91 */
++ pps_payload->nsl_bpg_offset =
++ cpu_to_be16(dsc_cfg->nsl_bpg_offset);
++
++ /* PPS 92, 93 */
++ pps_payload->second_line_offset_adj =
++ cpu_to_be16(dsc_cfg->second_line_offset_adj);
++
++ /* PPS 94 - 127 are O */
++}
++EXPORT_SYMBOL(drm_dsc_pps_payload_pack);
++
++/**
++ * drm_dsc_compute_rc_parameters() - Write rate control
++ * parameters to the dsc configuration defined in
++ * &struct drm_dsc_config in accordance with the DSC 1.2
++ * specification. Some configuration fields must be present
++ * beforehand.
++ *
++ * @vdsc_cfg:
++ * DSC Configuration data partially filled by driver
++ */
++int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg)
++{
++ unsigned long groups_per_line = 0;
++ unsigned long groups_total = 0;
++ unsigned long num_extra_mux_bits = 0;
++ unsigned long slice_bits = 0;
++ unsigned long hrd_delay = 0;
++ unsigned long final_scale = 0;
++ unsigned long rbs_min = 0;
++
++ if (vdsc_cfg->native_420 || vdsc_cfg->native_422) {
++ /* Number of groups used to code each line of a slice */
++ groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width / 2,
++ DSC_RC_PIXELS_PER_GROUP);
++
++ /* chunksize in Bytes */
++ vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width / 2 *
++ vdsc_cfg->bits_per_pixel,
++ (8 * 16));
++ } else {
++ /* Number of groups used to code each line of a slice */
++ groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width,
++ DSC_RC_PIXELS_PER_GROUP);
++
++ /* chunksize in Bytes */
++ vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width *
++ vdsc_cfg->bits_per_pixel,
++ (8 * 16));
++ }
++
++ if (vdsc_cfg->convert_rgb)
++ num_extra_mux_bits = 3 * (vdsc_cfg->mux_word_size +
++ (4 * vdsc_cfg->bits_per_component + 4)
++ - 2);
++ else if (vdsc_cfg->native_422)
++ num_extra_mux_bits = 4 * vdsc_cfg->mux_word_size +
++ (4 * vdsc_cfg->bits_per_component + 4) +
++ 3 * (4 * vdsc_cfg->bits_per_component) - 2;
++ else
++ num_extra_mux_bits = 3 * vdsc_cfg->mux_word_size +
++ (4 * vdsc_cfg->bits_per_component + 4) +
++ 2 * (4 * vdsc_cfg->bits_per_component) - 2;
++ /* Number of bits in one Slice */
++ slice_bits = 8 * vdsc_cfg->slice_chunk_size * vdsc_cfg->slice_height;
++
++ while ((num_extra_mux_bits > 0) &&
++ ((slice_bits - num_extra_mux_bits) % vdsc_cfg->mux_word_size))
++ num_extra_mux_bits--;
++
++ if (groups_per_line < vdsc_cfg->initial_scale_value - 8)
++ vdsc_cfg->initial_scale_value = groups_per_line + 8;
++
++ /* scale_decrement_interval calculation according to DSC spec 1.11 */
++ if (vdsc_cfg->initial_scale_value > 8)
++ vdsc_cfg->scale_decrement_interval = groups_per_line /
++ (vdsc_cfg->initial_scale_value - 8);
++ else
++ vdsc_cfg->scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX;
++
++ vdsc_cfg->final_offset = vdsc_cfg->rc_model_size -
++ (vdsc_cfg->initial_xmit_delay *
++ vdsc_cfg->bits_per_pixel + 8) / 16 + num_extra_mux_bits;
++
++ if (vdsc_cfg->final_offset >= vdsc_cfg->rc_model_size) {
++ DRM_DEBUG_KMS("FinalOfs < RcModelSze for this InitialXmitDelay\n");
++ return -ERANGE;
++ }
++
++ final_scale = (vdsc_cfg->rc_model_size * 8) /
++ (vdsc_cfg->rc_model_size - vdsc_cfg->final_offset);
++ if (vdsc_cfg->slice_height > 1)
++ /*
++ * NflBpgOffset is 16 bit value with 11 fractional bits
++ * hence we multiply by 2^11 for preserving the
++ * fractional part
++ */
++ vdsc_cfg->nfl_bpg_offset = DIV_ROUND_UP((vdsc_cfg->first_line_bpg_offset << 11),
++ (vdsc_cfg->slice_height - 1));
++ else
++ vdsc_cfg->nfl_bpg_offset = 0;
++
++ /* 2^16 - 1 */
++ if (vdsc_cfg->nfl_bpg_offset > 65535) {
++ DRM_DEBUG_KMS("NflBpgOffset is too large for this slice height\n");
++ return -ERANGE;
++ }
++
++ /* Number of groups used to code the entire slice */
++ groups_total = groups_per_line * vdsc_cfg->slice_height;
++
++ /* slice_bpg_offset is 16 bit value with 11 fractional bits */
++ vdsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((vdsc_cfg->rc_model_size -
++ vdsc_cfg->initial_offset +
++ num_extra_mux_bits) << 11),
++ groups_total);
++
++ if (final_scale > 9) {
++ /*
++ * ScaleIncrementInterval =
++ * finaloffset/((NflBpgOffset + SliceBpgOffset)*8(finalscale - 1.125))
++ * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional value,
++ * we need divide by 2^11 from pstDscCfg values
++ */
++ vdsc_cfg->scale_increment_interval =
++ (vdsc_cfg->final_offset * (1 << 11)) /
++ ((vdsc_cfg->nfl_bpg_offset +
++ vdsc_cfg->slice_bpg_offset) *
++ (final_scale - 9));
++ } else {
++ /*
++ * If finalScaleValue is less than or equal to 9, a value of 0 should
++ * be used to disable the scale increment at the end of the slice
++ */
++ vdsc_cfg->scale_increment_interval = 0;
++ }
++
++ if (vdsc_cfg->scale_increment_interval > 65535) {
++ DRM_DEBUG_KMS("ScaleIncrementInterval is large for slice height\n");
++ return -ERANGE;
++ }
++
++ /*
++ * DSC spec mentions that bits_per_pixel specifies the target
++ * bits/pixel (bpp) rate that is used by the encoder,
++ * in steps of 1/16 of a bit per pixel
++ */
++ rbs_min = vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset +
++ DIV_ROUND_UP(vdsc_cfg->initial_xmit_delay *
++ vdsc_cfg->bits_per_pixel, 16) +
++ groups_per_line * vdsc_cfg->first_line_bpg_offset;
++
++ hrd_delay = DIV_ROUND_UP((rbs_min * 16), vdsc_cfg->bits_per_pixel);
++ vdsc_cfg->rc_bits = (hrd_delay * vdsc_cfg->bits_per_pixel) / 16;
++ vdsc_cfg->initial_dec_delay = hrd_delay - vdsc_cfg->initial_xmit_delay;
++
++ return 0;
++}
++EXPORT_SYMBOL(drm_dsc_compute_rc_parameters);
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c b/drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c
+new file mode 100644
+index 000000000000..0ecd5065d120
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c
+@@ -0,0 +1,243 @@
++/*
++ * Copyright 2018 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++
++#include "dc.h"
++#include "dsc.h"
++#include "dc_hw_types.h"
++#include <drm/drm_dp_helper.h>
++
++#define DC_LOGGER \
++ dsc->ctx->logger
++
++static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int *buff_block_size);
++static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *line_buff_bit_depth);
++static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput);
++static bool dsc_bpp_increment_div_from_dpcd(int bpp_increment_dpcd, uint32_t *bpp_increment_div);
++
++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);
++}
++
++void dsc_config_log(struct display_stream_compressor *dsc,
++ const struct dsc_config *config)
++{
++ DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst);
++ DC_LOG_DSC("\n\tnum_slices_h %d\n\tnum_slices_v %d\n\tbits_per_pixel %d\n\tcolor_depth %d",
++ config->dc_dsc_cfg.num_slices_h,
++ config->dc_dsc_cfg.num_slices_v,
++ config->dc_dsc_cfg.bits_per_pixel,
++ config->color_depth);
++}
++
++
++bool dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_data, struct dsc_dec_dpcd_caps *dsc_sink_caps)
++{
++ dsc_sink_caps->is_dsc_supported = (dpcd_dsc_data[DP_DSC_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_DECOMPRESSION_IS_SUPPORTED) != 0;
++ if (!dsc_sink_caps->is_dsc_supported)
++ return true;
++
++ dsc_sink_caps->dsc_version = dpcd_dsc_data[DP_DSC_REV - DP_DSC_SUPPORT];
++
++ {
++ int buff_block_size;
++ int buff_size;
++
++ if (!dsc_buff_block_size_from_dpcd(dpcd_dsc_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT], &buff_block_size))
++ return false;
++
++ buff_size = dpcd_dsc_data[DP_DSC_RC_BUF_SIZE - DP_DSC_SUPPORT] + 1;
++ dsc_sink_caps->rc_buffer_size = buff_size * buff_block_size;
++ }
++
++ dsc_sink_caps->slice_caps1.raw = dpcd_dsc_data[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT];
++ if (!dsc_line_buff_depth_from_dpcd(dpcd_dsc_data[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT], &dsc_sink_caps->lb_bit_depth))
++ return false;
++
++ dsc_sink_caps->is_block_pred_supported =
++ (dpcd_dsc_data[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_BLK_PREDICTION_IS_SUPPORTED) != 0;
++
++ dsc_sink_caps->edp_max_bits_per_pixel =
++ dpcd_dsc_data[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] |
++ dpcd_dsc_data[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] << 8;
++
++ dsc_sink_caps->color_formats.raw = dpcd_dsc_data[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT];
++ dsc_sink_caps->color_depth.raw = dpcd_dsc_data[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT];
++
++ {
++ int dpcd_throughput = dpcd_dsc_data[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT];
++
++ if (!dsc_throughput_from_dpcd(dpcd_throughput & DP_DSC_THROUGHPUT_MODE_0_MASK, &dsc_sink_caps->throughput_mode_0_mps))
++ return false;
++
++ dpcd_throughput = (dpcd_throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> DP_DSC_THROUGHPUT_MODE_1_SHIFT;
++ if (!dsc_throughput_from_dpcd(dpcd_throughput, &dsc_sink_caps->throughput_mode_1_mps))
++ return false;
++ }
++
++ dsc_sink_caps->max_slice_width = dpcd_dsc_data[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] * 320;
++ dsc_sink_caps->slice_caps2.raw = dpcd_dsc_data[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT];
++
++ if (!dsc_bpp_increment_div_from_dpcd(dpcd_dsc_data[DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT], &dsc_sink_caps->bpp_increment_div))
++ return false;
++
++ return true;
++}
++
++
++/* This module's internal functions */
++
++static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int *buff_block_size)
++{
++
++ switch (dpcd_buff_block_size) {
++ case DP_DSC_RC_BUF_BLK_SIZE_1:
++ *buff_block_size = 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_4:
++ *buff_block_size = 4 * 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_16:
++ *buff_block_size = 16 * 1024;
++ break;
++ case DP_DSC_RC_BUF_BLK_SIZE_64:
++ *buff_block_size = 64 * 1024;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC buffer size not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++
++static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *line_buff_bit_depth)
++{
++ if (0 <= dpcd_line_buff_bit_depth && dpcd_line_buff_bit_depth <= 7)
++ *line_buff_bit_depth = dpcd_line_buff_bit_depth + 9;
++ else if (dpcd_line_buff_bit_depth == 8)
++ *line_buff_bit_depth = 8;
++ else {
++ dm_error("%s: DPCD DSC buffer depth not recoginzed.\n", __func__);
++ return false;
++ }
++
++ return true;
++}
++
++
++static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput)
++{
++ switch (dpcd_throughput) {
++ case DP_DSC_THROUGHPUT_MODE_0_340:
++ *throughput = 340;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_400:
++ *throughput = 400;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_450:
++ *throughput = 450;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_500:
++ *throughput = 500;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_550:
++ *throughput = 550;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_600:
++ *throughput = 600;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_650:
++ *throughput = 650;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_700:
++ *throughput = 700;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_750:
++ *throughput = 750;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_800:
++ *throughput = 800;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_850:
++ *throughput = 850;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_900:
++ *throughput = 900;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_950:
++ *throughput = 950;
++ break;
++ case DP_DSC_THROUGHPUT_MODE_0_1000:
++ *throughput = 1000;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC througput mode not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++
++static bool dsc_bpp_increment_div_from_dpcd(int bpp_increment_dpcd, uint32_t *bpp_increment_div)
++{
++
++ switch (bpp_increment_dpcd) {
++ case 0:
++ *bpp_increment_div = 16;
++ break;
++ case 1:
++ *bpp_increment_div = 8;
++ break;
++ case 2:
++ *bpp_increment_div = 4;
++ break;
++ case 3:
++ *bpp_increment_div = 2;
++ break;
++ case 4:
++ *bpp_increment_div = 1;
++ break;
++ default: {
++ dm_error("%s: DPCD DSC bits-per-pixel increment not recoginzed.\n", __func__);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++
++#endif // CONFIG_DRM_AMD_DC_DSC_SUPPORT
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
+new file mode 100644
+index 000000000000..020ad8f685ea
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
+@@ -0,0 +1,54 @@
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#ifndef __DSCC_TYPES_H__
++#define __DSCC_TYPES_H__
++
++#include <drm/drm_dsc.h>
++
++#ifndef NUM_BUF_RANGES
++#define NUM_BUF_RANGES 15
++#endif
++
++struct dsc_pps_rc_range {
++ int range_min_qp;
++ int range_max_qp;
++ int range_bpg_offset;
++};
++
++struct dsc_parameters {
++ struct drm_dsc_config pps;
++
++ /* Additional parameters for register programming */
++ uint32_t bytes_per_pixel; /* In u3.28 format */
++ uint32_t rc_buffer_model_size;
++};
++
++int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params);
++
++#endif
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h
+new file mode 100644
+index 000000000000..f66d006eac5d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h
+@@ -0,0 +1,706 @@
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++
++const qp_table qp_table_422_10bpc_min = {
++ { 6, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} },
++ { 6.5, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} },
++ { 7, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 7, 9, 9, 9, 11, 15} },
++ { 7.5, { 0, 2, 4, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11, 15} },
++ { 8, { 0, 2, 3, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 11, 14} },
++ { 8.5, { 0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 14} },
++ { 9, { 0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 13} },
++ { 9.5, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 13} },
++ { 10, { 0, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12} },
++ {10.5, { 0, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 11, 12} },
++ { 11, { 0, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11} },
++ {11.5, { 0, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 10, 11} },
++ { 12, { 0, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10} },
++ {12.5, { 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} },
++ { 13, { 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 9} },
++ {13.5, { 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 9} },
++ { 14, { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 7, 8} },
++ {14.5, { 0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8} },
++ { 15, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6, 6, 6, 8} },
++ {15.5, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7} },
++ { 16, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7} },
++ {16.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6} },
++ { 17, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 6} },
++ {17.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} },
++ { 18, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 5} },
++ {18.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 5} },
++ { 19, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 4} },
++ {19.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 4} },
++ { 20, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 3} }
++};
++
++
++const qp_table qp_table_444_8bpc_max = {
++ { 6, { 4, 6, 8, 8, 9, 9, 9, 10, 11, 12, 12, 12, 12, 13, 15} },
++ { 6.5, { 4, 6, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 12, 13, 15} },
++ { 7, { 4, 5, 7, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 13, 14} },
++ { 7.5, { 4, 5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 11, 12, 13, 14} },
++ { 8, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
++ { 8.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
++ { 9, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 13} },
++ { 9.5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 13} },
++ { 10, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} },
++ {10.5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 10, 11, 12} },
++ { 11, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11} },
++ {11.5, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} },
++ { 12, { 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9, 9, 9, 10, 11} },
++ {12.5, { 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} },
++ { 13, { 1, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 10} },
++ {13.5, { 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10} },
++ { 14, { 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} },
++ {14.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9} },
++ { 15, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} },
++ {15.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} },
++ { 16, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8} },
++ {16.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8} },
++ { 17, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 8} },
++ {17.5, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 8} },
++ { 18, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7} },
++ {18.5, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7} },
++ { 19, { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6} },
++ {19.5, { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6} },
++ { 20, { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 6} },
++ {20.5, { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 6} },
++ { 21, { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} },
++ {21.5, { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} },
++ { 22, { 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} },
++ {22.5, { 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} },
++ { 23, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4} },
++ {23.5, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4} },
++ { 24, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4} }
++};
++
++
++const qp_table qp_table_420_12bpc_max = {
++ { 4, {11, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 21, 22} },
++ { 4.5, {10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
++ { 5, { 9, 11, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 21} },
++ { 5.5, { 8, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 19, 20} },
++ { 6, { 6, 9, 11, 12, 13, 14, 15, 16, 16, 17, 17, 17, 17, 18, 19} },
++ { 6.5, { 6, 8, 10, 11, 11, 13, 14, 15, 15, 16, 16, 17, 17, 18, 19} },
++ { 7, { 5, 7, 9, 10, 10, 12, 13, 14, 14, 15, 16, 16, 17, 17, 18} },
++ { 7.5, { 5, 7, 8, 9, 9, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17} },
++ { 8, { 4, 6, 7, 8, 8, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17} },
++ { 8.5, { 3, 6, 6, 7, 7, 10, 11, 12, 13, 13, 14, 14, 15, 15, 16} },
++ { 9, { 3, 5, 6, 7, 7, 10, 11, 12, 12, 13, 13, 14, 14, 14, 15} },
++ { 9.5, { 2, 5, 6, 6, 7, 9, 10, 11, 12, 12, 13, 13, 13, 14, 15} },
++ { 10, { 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 15} },
++ {10.5, { 2, 3, 5, 5, 6, 7, 8, 9, 11, 11, 12, 12, 12, 12, 14} },
++ { 11, { 1, 3, 4, 5, 6, 6, 7, 9, 10, 11, 11, 11, 12, 12, 13} },
++ {11.5, { 1, 2, 3, 4, 5, 6, 6, 8, 9, 10, 10, 11, 11, 11, 13} },
++ { 12, { 1, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 10, 12} },
++ {12.5, { 1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 10, 11} },
++ { 13, { 1, 1, 1, 2, 4, 4, 6, 6, 7, 8, 8, 9, 9, 9, 11} },
++ {13.5, { 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8, 9, 11} },
++ { 14, { 1, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} },
++ {14.5, { 0, 1, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} },
++ { 15, { 0, 1, 1, 1, 1, 2, 3, 3, 5, 5, 5, 6, 6, 7, 9} },
++ {15.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8} },
++ { 16, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 7} },
++ {16.5, { 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 7} },
++ { 17, { 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 6} },
++ {17.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6} },
++ { 18, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 5} }
++};
++
++
++const qp_table qp_table_444_10bpc_min = {
++ { 6, { 0, 4, 7, 7, 9, 9, 9, 9, 9, 10, 10, 10, 10, 12, 18} },
++ { 6.5, { 0, 4, 6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 12, 18} },
++ { 7, { 0, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 10, 10, 12, 17} },
++ { 7.5, { 0, 4, 6, 6, 7, 8, 8, 8, 8, 8, 9, 9, 10, 12, 17} },
++ { 8, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 8, 9, 9, 9, 12, 16} },
++ { 8.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 8, 9, 9, 9, 12, 16} },
++ { 9, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
++ { 9.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
++ { 10, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 15} },
++ {10.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 15} },
++ { 11, { 0, 3, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} },
++ {11.5, { 0, 3, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} },
++ { 12, { 0, 2, 4, 4, 6, 6, 7, 7, 7, 7, 9, 9, 9, 11, 14} },
++ {12.5, { 0, 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 9, 9, 11, 14} },
++ { 13, { 0, 2, 4, 4, 5, 6, 7, 7, 7, 7, 8, 9, 9, 11, 13} },
++ {13.5, { 0, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9, 9, 11, 13} },
++ { 14, { 0, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 11, 13} },
++ {14.5, { 0, 2, 3, 4, 5, 5, 6, 6, 6, 7, 7, 8, 9, 11, 12} },
++ { 15, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 11, 12} },
++ {15.5, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 11, 12} },
++ { 16, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 8, 10, 11} },
++ {16.5, { 0, 1, 2, 3, 4, 5, 5, 6, 6, 6, 7, 8, 8, 10, 11} },
++ { 17, { 0, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8, 9, 11} },
++ {17.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 11} },
++ { 18, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} },
++ {18.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} },
++ { 19, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9} },
++ {19.5, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9} },
++ { 20, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 9} },
++ {20.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 9} },
++ { 21, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6, 6, 7, 9} },
++ {21.5, { 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 8} },
++ { 22, { 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 8} },
++ {22.5, { 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} },
++ { 23, { 0, 0, 1, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 7} },
++ {23.5, { 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 7} },
++ { 24, { 0, 0, 0, 1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 7} },
++ {24.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 7} },
++ { 25, { 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} },
++ {25.5, { 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} },
++ { 26, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 5} },
++ {26.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 5} },
++ { 27, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} },
++ {27.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} },
++ { 28, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 4} },
++ {28.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 4} },
++ { 29, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3} },
++ {29.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3} },
++ { 30, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} }
++};
++
++
++const qp_table qp_table_420_8bpc_max = {
++ { 4, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 13, 14} },
++ { 4.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
++ { 5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 13} },
++ { 5.5, { 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12} },
++ { 6, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} },
++ { 6.5, { 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} },
++ { 7, { 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10} },
++ { 7.5, { 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9} },
++ { 8, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} },
++ { 8.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8} },
++ { 9, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7} },
++ { 9.5, { 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} },
++ { 10, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6} },
++ {10.5, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} },
++ { 11, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5} },
++ {11.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} },
++ { 12, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4} }
++};
++
++
++const qp_table qp_table_444_8bpc_min = {
++ { 6, { 0, 1, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 6, 9, 14} },
++ { 6.5, { 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 9, 14} },
++ { 7, { 0, 0, 2, 2, 4, 4, 4, 4, 4, 5, 5, 6, 6, 9, 13} },
++ { 7.5, { 0, 0, 2, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 9, 13} },
++ { 8, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 4, 5, 5, 5, 8, 12} },
++ { 8.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 4, 5, 5, 5, 8, 12} },
++ { 9, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12} },
++ { 9.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12} },
++ { 10, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
++ {10.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
++ { 11, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} },
++ {11.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} },
++ { 12, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} },
++ {12.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 4, 5, 5, 7, 10} },
++ { 13, { 0, 0, 1, 1, 2, 3, 3, 3, 3, 3, 4, 5, 5, 7, 9} },
++ {13.5, { 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} },
++ { 14, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 5, 5, 7, 9} },
++ {14.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 7, 8} },
++ { 15, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} },
++ {15.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} },
++ { 16, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} },
++ {16.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} },
++ { 17, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} },
++ {17.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} },
++ { 18, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} },
++ {18.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} },
++ { 19, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5} },
++ {19.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5} },
++ { 20, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5} },
++ {20.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5} },
++ { 21, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} },
++ {21.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} },
++ { 22, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} },
++ {22.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} },
++ { 23, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} },
++ {23.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} },
++ { 24, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3} }
++};
++
++
++const qp_table qp_table_444_12bpc_min = {
++ { 6, { 0, 5, 11, 11, 13, 13, 13, 13, 13, 14, 14, 14, 14, 17, 22} },
++ { 6.5, { 0, 5, 10, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 17, 22} },
++ { 7, { 0, 5, 10, 10, 12, 12, 12, 12, 12, 13, 13, 14, 14, 17, 21} },
++ { 7.5, { 0, 5, 9, 10, 11, 12, 12, 12, 12, 12, 13, 13, 14, 17, 21} },
++ { 8, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 12, 13, 13, 13, 16, 20} },
++ { 8.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 12, 13, 13, 13, 16, 20} },
++ { 9, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
++ { 9.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
++ { 10, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
++ {10.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
++ { 11, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ {11.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ { 12, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ {12.5, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ { 13, { 0, 4, 7, 8, 9, 11, 11, 11, 11, 11, 13, 13, 13, 15, 17} },
++ {13.5, { 0, 3, 6, 7, 9, 10, 10, 11, 11, 11, 12, 13, 13, 15, 17} },
++ { 14, { 0, 3, 5, 6, 9, 9, 9, 10, 11, 11, 12, 13, 13, 15, 17} },
++ {14.5, { 0, 2, 5, 6, 8, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ { 15, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ {15.5, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ { 16, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 11, 12, 12, 14, 15} },
++ {16.5, { 0, 2, 3, 5, 7, 8, 9, 10, 11, 11, 11, 12, 12, 14, 15} },
++ { 17, { 0, 2, 3, 5, 5, 6, 9, 9, 10, 10, 11, 11, 12, 13, 15} },
++ {17.5, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 15} },
++ { 18, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 14} },
++ {18.5, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 14} },
++ { 19, { 0, 1, 2, 4, 5, 5, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ {19.5, { 0, 1, 2, 4, 5, 5, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ { 20, { 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 9, 10, 10, 11, 13} },
++ {20.5, { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 13} },
++ { 21, { 0, 1, 2, 3, 4, 5, 5, 7, 7, 8, 9, 10, 10, 11, 13} },
++ {21.5, { 0, 1, 2, 3, 3, 4, 5, 7, 7, 8, 9, 10, 10, 11, 12} },
++ { 22, { 0, 0, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 12} },
++ {22.5, { 0, 0, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11} },
++ { 23, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 7, 9, 9, 9, 9, 11} },
++ {23.5, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 7, 9, 9, 9, 9, 11} },
++ { 24, { 0, 0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 8, 9, 11} },
++ {24.5, { 0, 0, 1, 2, 3, 4, 4, 6, 6, 7, 8, 8, 8, 9, 11} },
++ { 25, { 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 10} },
++ {25.5, { 0, 0, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} },
++ { 26, { 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 7, 7, 9} },
++ {26.5, { 0, 0, 1, 2, 2, 3, 4, 5, 5, 5, 7, 7, 7, 7, 9} },
++ { 27, { 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} },
++ {27.5, { 0, 0, 1, 1, 2, 2, 4, 4, 4, 5, 6, 7, 7, 7, 9} },
++ { 28, { 0, 0, 0, 1, 1, 2, 3, 4, 4, 4, 6, 6, 6, 7, 9} },
++ {28.5, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 8} },
++ { 29, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8} },
++ {29.5, { 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7} },
++ { 30, { 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 5, 5, 5, 5, 7} },
++ {30.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 7} },
++ { 31, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 7} },
++ {31.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} },
++ { 32, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6} },
++ {32.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 6} },
++ { 33, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} },
++ {33.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} },
++ { 34, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 5} },
++ {34.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 5} },
++ { 35, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} },
++ {35.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 4} },
++ { 36, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} }
++};
++
++
++const qp_table qp_table_420_12bpc_min = {
++ { 4, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21} },
++ { 4.5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
++ { 5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} },
++ { 5.5, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
++ { 6, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ { 6.5, { 0, 4, 6, 8, 9, 10, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ { 7, { 0, 3, 5, 7, 9, 10, 10, 11, 11, 11, 13, 13, 13, 15, 17} },
++ { 7.5, { 0, 3, 5, 7, 8, 9, 10, 10, 11, 11, 12, 13, 13, 15, 16} },
++ { 8, { 0, 2, 4, 6, 7, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ { 8.5, { 0, 2, 4, 6, 6, 9, 9, 10, 11, 11, 12, 12, 13, 14, 15} },
++ { 9, { 0, 2, 4, 6, 6, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14} },
++ { 9.5, { 0, 2, 4, 5, 6, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14} },
++ { 10, { 0, 2, 3, 5, 6, 7, 8, 8, 9, 10, 10, 12, 12, 12, 14} },
++ {10.5, { 0, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 11, 11, 13} },
++ { 11, { 0, 2, 3, 4, 5, 5, 6, 8, 8, 9, 9, 10, 11, 11, 12} },
++ {11.5, { 0, 1, 2, 3, 4, 5, 5, 7, 8, 8, 9, 10, 10, 10, 12} },
++ { 12, { 0, 0, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 11} },
++ {12.5, { 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 10} },
++ { 13, { 0, 0, 0, 1, 3, 3, 5, 5, 6, 7, 7, 8, 8, 8, 10} },
++ {13.5, { 0, 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 7, 8, 10} },
++ { 14, { 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 7, 9} },
++ {14.5, { 0, 0, 0, 0, 1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 8} },
++ { 15, { 0, 0, 0, 0, 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 8} },
++ {15.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} },
++ { 16, { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 6} },
++ {16.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6} },
++ { 17, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 5} },
++ {17.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 5} },
++ { 18, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 4} }
++};
++
++
++const qp_table qp_table_422_12bpc_min = {
++ { 6, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} },
++ { 6.5, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} },
++ { 7, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
++ { 7.5, { 0, 4, 8, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} },
++ { 8, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} },
++ { 8.5, { 0, 3, 6, 8, 9, 10, 10, 11, 11, 11, 12, 13, 13, 15, 18} },
++ { 9, { 0, 3, 5, 8, 9, 10, 10, 10, 11, 11, 12, 13, 13, 15, 17} },
++ { 9.5, { 0, 3, 5, 7, 8, 9, 10, 10, 11, 11, 12, 13, 13, 15, 17} },
++ { 10, { 0, 2, 4, 6, 7, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ {10.5, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} },
++ { 11, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 14, 15} },
++ {11.5, { 0, 2, 4, 6, 7, 7, 9, 9, 10, 11, 11, 12, 12, 14, 15} },
++ { 12, { 0, 2, 4, 6, 6, 6, 8, 8, 9, 9, 11, 11, 12, 13, 14} },
++ {12.5, { 0, 1, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 13, 14} },
++ { 13, { 0, 1, 3, 4, 5, 5, 7, 8, 8, 9, 10, 10, 11, 12, 13} },
++ {13.5, { 0, 1, 3, 3, 4, 5, 7, 7, 8, 8, 10, 10, 10, 12, 13} },
++ { 14, { 0, 0, 2, 3, 4, 5, 6, 6, 7, 7, 9, 10, 10, 11, 12} },
++ {14.5, { 0, 0, 1, 3, 4, 4, 6, 6, 6, 7, 9, 9, 9, 11, 12} },
++ { 15, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 6, 8, 9, 9, 10, 12} },
++ {15.5, { 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 8, 8, 8, 10, 11} },
++ { 16, { 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 8, 8, 8, 9, 11} },
++ {16.5, { 0, 0, 0, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7, 9, 10} },
++ { 17, { 0, 0, 0, 1, 2, 2, 4, 4, 4, 5, 6, 6, 6, 8, 10} },
++ {17.5, { 0, 0, 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 8, 9} },
++ { 18, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 9} },
++ {18.5, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 3, 5, 5, 5, 7, 9} },
++ { 19, { 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 8} },
++ {19.5, { 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 6, 8} },
++ { 20, { 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 7} },
++ {20.5, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 7} },
++ { 21, { 0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6} },
++ {21.5, { 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 6} },
++ { 22, { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 6} },
++ {22.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 5} },
++ { 23, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 5} },
++ {23.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 4} },
++ { 24, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 4} }
++};
++
++
++const qp_table qp_table_422_12bpc_max = {
++ { 6, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
++ { 6.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
++ { 7, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} },
++ { 7.5, { 9, 10, 12, 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 20} },
++ { 8, { 6, 9, 10, 12, 14, 15, 15, 16, 16, 17, 17, 17, 17, 18, 19} },
++ { 8.5, { 6, 8, 9, 11, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 19} },
++ { 9, { 5, 7, 8, 10, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 18} },
++ { 9.5, { 5, 7, 7, 9, 10, 12, 12, 13, 14, 14, 15, 15, 16, 17, 18} },
++ { 10, { 4, 6, 6, 8, 9, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} },
++ {10.5, { 4, 6, 6, 8, 9, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17} },
++ { 11, { 4, 5, 6, 8, 9, 10, 11, 12, 13, 13, 14, 14, 15, 15, 16} },
++ {11.5, { 3, 5, 6, 8, 9, 9, 11, 11, 12, 13, 13, 14, 14, 15, 16} },
++ { 12, { 3, 5, 6, 8, 8, 8, 10, 10, 11, 11, 13, 13, 14, 14, 15} },
++ {12.5, { 3, 4, 6, 7, 8, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15} },
++ { 13, { 2, 4, 5, 6, 7, 7, 9, 10, 10, 11, 12, 12, 13, 13, 14} },
++ {13.5, { 2, 4, 5, 5, 6, 7, 9, 9, 10, 10, 12, 12, 12, 13, 14} },
++ { 14, { 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 11, 12, 12, 12, 13} },
++ {14.5, { 2, 3, 3, 5, 6, 6, 8, 8, 8, 9, 11, 11, 11, 12, 13} },
++ { 15, { 2, 3, 3, 5, 5, 6, 7, 8, 8, 8, 10, 11, 11, 11, 13} },
++ {15.5, { 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 10, 10, 10, 11, 12} },
++ { 16, { 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 10, 10, 10, 10, 12} },
++ {16.5, { 1, 2, 2, 4, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 11} },
++ { 17, { 1, 1, 2, 3, 4, 4, 6, 6, 6, 7, 8, 8, 8, 9, 11} },
++ {17.5, { 1, 1, 2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 9, 10} },
++ { 18, { 1, 1, 1, 2, 3, 3, 5, 5, 5, 6, 7, 7, 8, 8, 10} },
++ {18.5, { 1, 1, 1, 2, 3, 3, 5, 5, 5, 5, 7, 7, 7, 8, 10} },
++ { 19, { 1, 1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 7, 9} },
++ {19.5, { 1, 1, 1, 2, 2, 2, 4, 5, 5, 5, 6, 6, 6, 7, 9} },
++ { 20, { 1, 1, 1, 2, 2, 2, 4, 5, 5, 5, 6, 6, 6, 6, 8} },
++ {20.5, { 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 8} },
++ { 21, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 7} },
++ {21.5, { 0, 0, 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 7} },
++ { 22, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 7} },
++ {22.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 6} },
++ { 23, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6} },
++ {23.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5} },
++ { 24, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5} }
++};
++
++
++const qp_table qp_table_444_12bpc_max = {
++ { 6, {12, 14, 16, 16, 17, 17, 17, 18, 19, 20, 20, 20, 20, 21, 23} },
++ { 6.5, {12, 14, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 20, 21, 23} },
++ { 7, {12, 13, 15, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 21, 22} },
++ { 7.5, {12, 13, 14, 15, 15, 16, 16, 17, 18, 18, 19, 19, 20, 21, 22} },
++ { 8, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
++ { 8.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} },
++ { 9, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 21} },
++ { 9.5, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 21} },
++ { 10, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} },
++ {10.5, {10, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 18, 19, 20} },
++ { 11, { 9, 11, 13, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19} },
++ {11.5, { 9, 11, 13, 14, 15, 15, 15, 16, 16, 17, 17, 17, 17, 18, 19} },
++ { 12, { 6, 9, 12, 13, 14, 14, 15, 16, 16, 17, 17, 17, 17, 18, 19} },
++ {12.5, { 6, 9, 12, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 19} },
++ { 13, { 5, 9, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 17, 18} },
++ {13.5, { 5, 8, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 18} },
++ { 14, { 5, 8, 10, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 18} },
++ {14.5, { 4, 7, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17} },
++ { 15, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} },
++ {15.5, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} },
++ { 16, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 13, 14, 14, 15, 16} },
++ {16.5, { 4, 5, 7, 8, 10, 11, 11, 12, 13, 13, 13, 14, 14, 15, 16} },
++ { 17, { 4, 5, 7, 8, 8, 9, 11, 11, 12, 12, 12, 13, 13, 14, 16} },
++ {17.5, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 16} },
++ { 18, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 15} },
++ {18.5, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 15} },
++ { 19, { 3, 4, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 14} },
++ {19.5, { 3, 4, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 14} },
++ { 20, { 2, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11, 11, 12, 14} },
++ {20.5, { 2, 3, 5, 5, 7, 8, 8, 8, 9, 10, 10, 11, 11, 12, 14} },
++ { 21, { 2, 3, 5, 5, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 14} },
++ {21.5, { 2, 3, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13} },
++ { 22, { 2, 2, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10, 10, 11, 13} },
++ {22.5, { 2, 2, 4, 5, 5, 6, 7, 7, 8, 9, 10, 10, 10, 11, 12} },
++ { 23, { 2, 2, 4, 5, 5, 6, 7, 7, 7, 8, 10, 10, 10, 10, 12} },
++ {23.5, { 2, 2, 3, 5, 5, 6, 7, 7, 7, 8, 10, 10, 10, 10, 12} },
++ { 24, { 2, 2, 3, 4, 4, 5, 7, 7, 7, 8, 9, 9, 9, 10, 12} },
++ {24.5, { 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 9, 10, 12} },
++ { 25, { 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 9, 9, 11} },
++ {25.5, { 1, 1, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9, 9, 9, 11} },
++ { 26, { 1, 1, 3, 3, 3, 4, 5, 6, 6, 7, 8, 8, 8, 8, 10} },
++ {26.5, { 1, 1, 2, 3, 3, 4, 5, 6, 6, 6, 8, 8, 8, 8, 10} },
++ { 27, { 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 10} },
++ {27.5, { 1, 1, 2, 2, 3, 3, 5, 5, 5, 6, 7, 8, 8, 8, 10} },
++ { 28, { 0, 1, 1, 2, 2, 3, 4, 5, 5, 5, 7, 7, 7, 8, 10} },
++ {28.5, { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} },
++ { 29, { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 9} },
++ {29.5, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8} },
++ { 30, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6, 6, 6, 8} },
++ {30.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8} },
++ { 31, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8} },
++ {31.5, { 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8} },
++ { 32, { 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 7} },
++ {32.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 7} },
++ { 33, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} },
++ {33.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} },
++ { 34, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6} },
++ {34.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 3, 3, 3, 4, 6} },
++ { 35, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} },
++ {35.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 5} },
++ { 36, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 4} }
++};
++
++
++const qp_table qp_table_420_8bpc_min = {
++ { 4, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 13} },
++ { 4.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
++ { 5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
++ { 5.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
++ { 6, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} },
++ { 6.5, { 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 5, 7, 10} },
++ { 7, { 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} },
++ { 7.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 7, 8} },
++ { 8, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} },
++ { 8.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} },
++ { 9, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6} },
++ { 9.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} },
++ { 10, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5} },
++ {10.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 5} },
++ { 11, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4} },
++ {11.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} },
++ { 12, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3} }
++};
++
++
++const qp_table qp_table_422_8bpc_min = {
++ { 6, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
++ { 6.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} },
++ { 7, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
++ { 7.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} },
++ { 8, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} },
++ { 8.5, { 0, 0, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 7, 10} },
++ { 9, { 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} },
++ { 9.5, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9} },
++ { 10, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} },
++ {10.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} },
++ { 11, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} },
++ {11.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} },
++ { 12, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6} },
++ {12.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} },
++ { 13, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5} },
++ {13.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5} },
++ { 14, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4} },
++ {14.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4} },
++ { 15, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 4} },
++ {15.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} },
++ { 16, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} }
++};
++
++
++const qp_table qp_table_422_10bpc_max = {
++ { 6, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
++ { 6.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
++ { 7, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} },
++ { 7.5, { 5, 6, 8, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16} },
++ { 8, { 4, 6, 7, 9, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 15} },
++ { 8.5, { 4, 5, 6, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15} },
++ { 9, { 3, 4, 5, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14} },
++ { 9.5, { 3, 4, 4, 6, 6, 8, 8, 9, 10, 10, 11, 11, 12, 13, 14} },
++ { 10, { 2, 3, 3, 5, 5, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ {10.5, { 2, 3, 3, 5, 5, 6, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ { 11, { 2, 3, 3, 5, 5, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12} },
++ {11.5, { 2, 3, 3, 5, 5, 5, 7, 7, 8, 9, 9, 10, 10, 11, 12} },
++ { 12, { 2, 3, 3, 5, 5, 5, 7, 7, 8, 8, 9, 9, 10, 10, 11} },
++ {12.5, { 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 11} },
++ { 13, { 1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10} },
++ {13.5, { 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 10} },
++ { 14, { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 9} },
++ {14.5, { 1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 7, 7, 8, 9} },
++ { 15, { 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7, 7, 7, 9} },
++ {15.5, { 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 8} },
++ { 16, { 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6, 8} },
++ {16.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7} },
++ { 17, { 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 7} },
++ {17.5, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6} },
++ { 18, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 6} },
++ {18.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 6} },
++ { 19, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 5} },
++ {19.5, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 5} },
++ { 20, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 4} }
++};
++
++
++const qp_table qp_table_420_10bpc_max = {
++ { 4, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 17, 18} },
++ { 4.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
++ { 5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 17} },
++ { 5.5, { 6, 7, 8, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 16} },
++ { 6, { 4, 6, 8, 9, 10, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15} },
++ { 6.5, { 4, 5, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 15} },
++ { 7, { 3, 4, 6, 7, 7, 8, 9, 10, 10, 11, 12, 12, 13, 13, 14} },
++ { 7.5, { 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 11, 11, 12, 12, 13} },
++ { 8, { 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ { 8.5, { 1, 3, 3, 4, 4, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12} },
++ { 9, { 1, 3, 3, 4, 4, 6, 7, 8, 8, 9, 9, 10, 10, 10, 11} },
++ { 9.5, { 1, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 10, 11} },
++ { 10, { 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 9, 11} },
++ {10.5, { 1, 1, 3, 3, 3, 4, 5, 5, 7, 7, 8, 8, 8, 8, 10} },
++ { 11, { 0, 1, 2, 3, 3, 3, 4, 5, 6, 7, 7, 7, 8, 8, 9} },
++ {11.5, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 7, 9} },
++ { 12, { 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 6, 8} },
++ {12.5, { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} },
++ { 13, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 7} },
++ {13.5, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} },
++ { 14, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} },
++ {14.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 5} },
++ { 15, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} }
++};
++
++
++const qp_table qp_table_420_10bpc_min = {
++ { 4, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 17} },
++ { 4.5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
++ { 5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} },
++ { 5.5, { 0, 3, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15} },
++ { 6, { 0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} },
++ { 6.5, { 0, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9, 9, 11, 14} },
++ { 7, { 0, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 11, 13} },
++ { 7.5, { 0, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 11, 12} },
++ { 8, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12} },
++ { 8.5, { 0, 2, 2, 3, 3, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11} },
++ { 9, { 0, 2, 2, 3, 3, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10} },
++ { 9.5, { 0, 2, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10} },
++ { 10, { 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 8, 8, 8, 10} },
++ {10.5, { 0, 0, 2, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} },
++ { 11, { 0, 0, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8} },
++ {11.5, { 0, 0, 0, 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 8} },
++ { 12, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 7} },
++ {12.5, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6} },
++ { 13, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} },
++ {13.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 5} },
++ { 14, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} },
++ {14.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 4} },
++ { 15, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} }
++};
++
++
++const qp_table qp_table_444_10bpc_max = {
++ { 6, { 8, 10, 12, 12, 13, 13, 13, 14, 15, 16, 16, 16, 16, 17, 19} },
++ { 6.5, { 8, 10, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 16, 17, 19} },
++ { 7, { 8, 9, 11, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 17, 18} },
++ { 7.5, { 8, 9, 10, 11, 11, 12, 12, 13, 14, 14, 15, 15, 16, 17, 18} },
++ { 8, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
++ { 8.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} },
++ { 9, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 17} },
++ { 9.5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 17} },
++ { 10, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} },
++ {10.5, { 6, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 14, 15, 16} },
++ { 11, { 5, 7, 9, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15} },
++ {11.5, { 5, 7, 9, 10, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 15} },
++ { 12, { 4, 6, 8, 9, 10, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15} },
++ {12.5, { 4, 6, 8, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15} },
++ { 13, { 3, 6, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 14} },
++ {13.5, { 3, 5, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14} },
++ { 14, { 3, 5, 6, 7, 8, 8, 8, 9, 10, 10, 11, 12, 12, 12, 14} },
++ {14.5, { 2, 4, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13} },
++ { 15, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ {15.5, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} },
++ { 16, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 12} },
++ {16.5, { 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 12} },
++ { 17, { 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 12} },
++ {17.5, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 12} },
++ { 18, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 11} },
++ {18.5, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 11} },
++ { 19, { 1, 2, 3, 4, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9, 10} },
++ {19.5, { 1, 2, 3, 4, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9, 10} },
++ { 20, { 1, 2, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 8, 10} },
++ {20.5, { 1, 2, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 10} },
++ { 21, { 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 7, 8, 10} },
++ {21.5, { 1, 2, 3, 3, 3, 3, 4, 5, 5, 5, 6, 7, 7, 8, 9} },
++ { 22, { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 9} },
++ {22.5, { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8} },
++ { 23, { 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 8} },
++ {23.5, { 1, 1, 1, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 8} },
++ { 24, { 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 8} },
++ {24.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 8} },
++ { 25, { 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7} },
++ {25.5, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 7} },
++ { 26, { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 6} },
++ {26.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 6} },
++ { 27, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} },
++ {27.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} },
++ { 28, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 5} },
++ {28.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} },
++ { 29, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4} },
++ {29.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4} },
++ { 30, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 4} }
++};
++
++
++const qp_table qp_table_422_8bpc_max = {
++ { 6, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
++ { 6.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} },
++ { 7, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} },
++ { 7.5, { 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12} },
++ { 8, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} },
++ { 8.5, { 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} },
++ { 9, { 1, 2, 3, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10} },
++ { 9.5, { 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 10} },
++ { 10, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} },
++ {10.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} },
++ { 11, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8} },
++ {11.5, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8} },
++ { 12, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7} },
++ {12.5, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7} },
++ { 13, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6} },
++ {13.5, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 6} },
++ { 14, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5} },
++ {14.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 5} },
++ { 15, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 5} },
++ {15.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} },
++ { 16, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} }
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c
+new file mode 100644
+index 000000000000..ca51e83f8764
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c
+@@ -0,0 +1,258 @@
++#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
++
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "os_types.h"
++#include "rc_calc.h"
++#include "qp_tables.h"
++
++#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min)
++
++#define MODE_SELECT(val444, val422, val420) \
++ (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420))
++
++
++#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \
++ table = qp_table_##mode##_##bpc##bpc_##max; \
++ table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \
++ break
++
++
++void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, enum max_min max_min, float bpp)
++{
++ int mode = MODE_SELECT(444, 422, 420);
++ int sel = table_hash(mode, bpc, max_min);
++ int table_size = 0;
++ int index;
++ const struct qp_entry *table = 0L;
++
++ // alias enum
++ enum { min = MM_MIN, max = MM_MAX };
++ switch (sel) {
++ TABLE_CASE(444, 8, max);
++ TABLE_CASE(444, 8, min);
++ TABLE_CASE(444, 10, max);
++ TABLE_CASE(444, 10, min);
++ TABLE_CASE(444, 12, max);
++ TABLE_CASE(444, 12, min);
++ TABLE_CASE(422, 8, max);
++ TABLE_CASE(422, 8, min);
++ TABLE_CASE(422, 10, max);
++ TABLE_CASE(422, 10, min);
++ TABLE_CASE(422, 12, max);
++ TABLE_CASE(422, 12, min);
++ TABLE_CASE(420, 8, max);
++ TABLE_CASE(420, 8, min);
++ TABLE_CASE(420, 10, max);
++ TABLE_CASE(420, 10, min);
++ TABLE_CASE(420, 12, max);
++ TABLE_CASE(420, 12, min);
++ }
++
++ if (table == 0)
++ return;
++
++ index = (bpp - table[0].bpp) * 2;
++
++ /* requested size is bigger than the table */
++ if (index >= table_size) {
++ dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n");
++ return;
++ }
++
++ memcpy(qps, table[index].qps, sizeof(qp_set));
++}
++
++double dsc_roundf(double num)
++{
++ if (num < 0.0)
++ num = num - 0.5;
++ else
++ num = num + 0.5;
++
++ return (int)(num);
++}
++
++double dsc_ceil(double num)
++{
++ double retval = (int)num;
++
++ if (retval != num && num > 0)
++ retval = num + 1;
++
++ return (int)retval;
++}
++
++void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp)
++{
++ int *p = ofs;
++
++ if (mode == CM_444 || mode == CM_RGB) {
++ *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0))))));
++ *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0))))));
++ *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0))))));
++ *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0))))));
++ *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0))))));
++ *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0))));
++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0))));
++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0))));
++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0))));
++ *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0))));
++ *p++ = -10;
++ *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0))));
++ *p++ = -12;
++ *p++ = -12;
++ *p++ = -12;
++ } else if (mode == CM_422) {
++ *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0))));
++ *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0))));
++ *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0))));
++ *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0))));
++ *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0))));
++ *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0))));
++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0))));
++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0))));
++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0))));
++ *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0))));
++ *p++ = -10;
++ *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1))));
++ *p++ = -12;
++ *p++ = -12;
++ *p++ = -12;
++ } else {
++ *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0))));
++ *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0))));
++ *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0))));
++ *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0))));
++ *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0))));
++ *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0))));
++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0))));
++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0))));
++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0))));
++ *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0))));
++ *p++ = -10;
++ *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0))));
++ *p++ = -12;
++ *p++ = -12;
++ *p++ = -12;
++ }
++}
++
++int median3(int a, int b, int c)
++{
++ if (a > b)
++ swap(a, b);
++ if (b > c)
++ swap(b, c);
++ if (a > b)
++ swap(b, c);
++
++ return b;
++}
++
++void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_comp bpc, float bpp, int slice_width, int slice_height, int minor_version)
++{
++ float bpp_group;
++ float initial_xmit_delay_factor;
++ int source_bpp;
++ int padding_pixels;
++ int i;
++
++ rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0);
++ rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0);
++
++ bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0);
++
++ switch (cm) {
++ case CM_420:
++ rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584)))));
++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group)));
++ rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group)));
++ break;
++ case CM_422:
++ rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584))));
++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group)));
++ rc->second_line_bpg_offset = 0;
++ break;
++ case CM_444:
++ case CM_RGB:
++ rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2)))));
++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group)));
++ rc->second_line_bpg_offset = 0;
++ break;
++ }
++
++ initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0;
++ rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor);
++
++ if (cm == CM_422 || cm == CM_420)
++ slice_width /= 2;
++
++ padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0;
++ if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) {
++ if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1)
++ rc->initial_xmit_delay++;
++ }
++
++ source_bpp = MODE_SELECT(bpc * 3, bpc * 2, bpc * 1.5);
++
++ rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0);
++ rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0);
++ rc->flatness_det_thresh = 2 << (bpc - 8);
++
++ get_qp_set(rc->qp_min, cm, bpc, MM_MIN, bpp);
++ get_qp_set(rc->qp_max, cm, bpc, MM_MAX, bpp);
++ if (cm == CM_444 && minor_version == 1) {
++ for (i = 0; i < QP_SET_SIZE; ++i) {
++ rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0;
++ rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0;
++ }
++ }
++ get_ofs_set(rc->ofs, cm, bpp);
++
++ /* fixed parameters */
++ rc->rc_model_size = 8192;
++ rc->rc_edge_factor = 6;
++ rc->rc_tgt_offset_hi = 3;
++ rc->rc_tgt_offset_lo = 3;
++
++ rc->rc_buf_thresh[0] = 896;
++ rc->rc_buf_thresh[1] = 1792;
++ rc->rc_buf_thresh[2] = 2688;
++ rc->rc_buf_thresh[3] = 3584;
++ rc->rc_buf_thresh[4] = 4480;
++ rc->rc_buf_thresh[5] = 5376;
++ rc->rc_buf_thresh[6] = 6272;
++ rc->rc_buf_thresh[7] = 6720;
++ rc->rc_buf_thresh[8] = 7168;
++ rc->rc_buf_thresh[9] = 7616;
++ rc->rc_buf_thresh[10] = 7744;
++ rc->rc_buf_thresh[11] = 7872;
++ rc->rc_buf_thresh[12] = 8000;
++ rc->rc_buf_thresh[13] = 8064;
++}
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h
+new file mode 100644
+index 000000000000..f1d6e793bc61
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h
+@@ -0,0 +1,85 @@
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __RC_CALC_H__
++#define __RC_CALC_H__
++
++
++#define QP_SET_SIZE 15
++
++typedef int qp_set[QP_SET_SIZE];
++
++struct rc_params {
++ int rc_quant_incr_limit0;
++ int rc_quant_incr_limit1;
++ int initial_fullness_offset;
++ int initial_xmit_delay;
++ int first_line_bpg_offset;
++ int second_line_bpg_offset;
++ int flatness_min_qp;
++ int flatness_max_qp;
++ int flatness_det_thresh;
++ qp_set qp_min;
++ qp_set qp_max;
++ qp_set ofs;
++ int rc_model_size;
++ int rc_edge_factor;
++ int rc_tgt_offset_hi;
++ int rc_tgt_offset_lo;
++ int rc_buf_thresh[QP_SET_SIZE - 1];
++};
++
++enum colour_mode {
++ CM_RGB, /* 444 RGB */
++ CM_444, /* 444 YUV or simple 422 */
++ CM_422, /* native 422 */
++ CM_420 /* native 420 */
++};
++
++enum bits_per_comp {
++ BPC_8 = 8,
++ BPC_10 = 10,
++ BPC_12 = 12
++};
++
++enum max_min {
++ MM_MIN = 0,
++ MM_MAX = 1
++};
++
++struct qp_entry {
++ float bpp;
++ const qp_set qps;
++};
++
++typedef struct qp_entry qp_table[];
++
++void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_comp bpc, float bpp, int slice_width, int slice_height, int minor_version);
++
++#endif
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
+new file mode 100644
+index 000000000000..73172fd0b529
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
+@@ -0,0 +1,147 @@
++#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
++/*
++ * Copyright 2012-17 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#include "os_types.h"
++#include <drm/drm_dsc.h>
++#include "dscc_types.h"
++#include "rc_calc.h"
++
++double dsc_ceil(double num);
++
++static void copy_pps_fields(struct drm_dsc_config *to, const struct drm_dsc_config *from)
++{
++ to->line_buf_depth = from->line_buf_depth;
++ to->bits_per_component = from->bits_per_component;
++ to->convert_rgb = from->convert_rgb;
++ to->slice_width = from->slice_width;
++ to->slice_height = from->slice_height;
++ to->simple_422 = from->simple_422;
++ to->native_422 = from->native_422;
++ to->native_420 = from->native_420;
++ to->pic_width = from->pic_width;
++ to->pic_height = from->pic_height;
++ to->rc_tgt_offset_high = from->rc_tgt_offset_high;
++ to->rc_tgt_offset_low = from->rc_tgt_offset_low;
++ to->bits_per_pixel = from->bits_per_pixel;
++ to->rc_edge_factor = from->rc_edge_factor;
++ to->rc_quant_incr_limit1 = from->rc_quant_incr_limit1;
++ to->rc_quant_incr_limit0 = from->rc_quant_incr_limit0;
++ to->initial_xmit_delay = from->initial_xmit_delay;
++ to->initial_dec_delay = from->initial_dec_delay;
++ to->block_pred_enable = from->block_pred_enable;
++ to->first_line_bpg_offset = from->first_line_bpg_offset;
++ to->second_line_bpg_offset = from->second_line_bpg_offset;
++ to->initial_offset = from->initial_offset;
++ memcpy(&to->rc_buf_thresh, &from->rc_buf_thresh, sizeof(from->rc_buf_thresh));
++ memcpy(&to->rc_range_params, &from->rc_range_params, sizeof(from->rc_range_params));
++ to->rc_model_size = from->rc_model_size;
++ to->flatness_min_qp = from->flatness_min_qp;
++ to->flatness_max_qp = from->flatness_max_qp;
++ to->initial_scale_value = from->initial_scale_value;
++ to->scale_decrement_interval = from->scale_decrement_interval;
++ to->scale_increment_interval = from->scale_increment_interval;
++ to->nfl_bpg_offset = from->nfl_bpg_offset;
++ to->nsl_bpg_offset = from->nsl_bpg_offset;
++ to->slice_bpg_offset = from->slice_bpg_offset;
++ to->final_offset = from->final_offset;
++ to->vbr_enable = from->vbr_enable;
++ to->slice_chunk_size = from->slice_chunk_size;
++ to->second_line_offset_adj = from->second_line_offset_adj;
++ to->dsc_version_minor = from->dsc_version_minor;
++}
++
++static void copy_rc_to_cfg(struct drm_dsc_config *dsc_cfg, const struct rc_params *rc)
++{
++ int i;
++
++ dsc_cfg->rc_quant_incr_limit0 = rc->rc_quant_incr_limit0;
++ dsc_cfg->rc_quant_incr_limit1 = rc->rc_quant_incr_limit1;
++ dsc_cfg->initial_offset = rc->initial_fullness_offset;
++ dsc_cfg->initial_xmit_delay = rc->initial_xmit_delay;
++ dsc_cfg->first_line_bpg_offset = rc->first_line_bpg_offset;
++ dsc_cfg->second_line_bpg_offset = rc->second_line_bpg_offset;
++ dsc_cfg->flatness_min_qp = rc->flatness_min_qp;
++ dsc_cfg->flatness_max_qp = rc->flatness_max_qp;
++ for (i = 0; i < QP_SET_SIZE; ++i) {
++ dsc_cfg->rc_range_params[i].range_min_qp = rc->qp_min[i];
++ dsc_cfg->rc_range_params[i].range_max_qp = rc->qp_max[i];
++ /* Truncate 8-bit signed value to 6-bit signed value */
++ dsc_cfg->rc_range_params[i].range_bpg_offset = 0x3f & rc->ofs[i];
++ }
++ dsc_cfg->rc_model_size = rc->rc_model_size;
++ dsc_cfg->rc_edge_factor = rc->rc_edge_factor;
++ dsc_cfg->rc_tgt_offset_high = rc->rc_tgt_offset_hi;
++ dsc_cfg->rc_tgt_offset_low = rc->rc_tgt_offset_lo;
++
++ for (i = 0; i < QP_SET_SIZE - 1; ++i)
++ dsc_cfg->rc_buf_thresh[i] = rc->rc_buf_thresh[i];
++}
++
++int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params)
++{
++ enum colour_mode mode = pps->convert_rgb ? CM_RGB :
++ (pps->simple_422 ? CM_444 :
++ (pps->native_422 ? CM_422 :
++ pps->native_420 ? CM_420 : CM_444));
++ enum bits_per_comp bpc = (pps->bits_per_component == 8) ? BPC_8 :
++ (pps->bits_per_component == 10) ? BPC_10 : BPC_12;
++ float bpp = ((float) pps->bits_per_pixel / 16.0);
++ int slice_width = pps->slice_width;
++ int slice_height = pps->slice_height;
++ int ret;
++ struct rc_params rc;
++ struct drm_dsc_config dsc_cfg;
++
++ double d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width;
++
++ // TODO: Make sure the formula for calculating this is precise (ceiling vs. floor, and at what point they should be applied)
++ if (pps->native_422 || pps->native_420)
++ d_bytes_per_pixel /= 2;
++
++ dsc_params->bytes_per_pixel = (uint32_t)dsc_ceil(d_bytes_per_pixel * 0x10000000);
++
++ /* in native_422 or native_420 modes, the bits_per_pixel is double the target bpp
++ * (the latter is what calc_rc_params expects)
++ */
++ if (pps->native_422 || pps->native_420)
++ bpp /= 2.0;
++
++ calc_rc_params(&rc, mode, bpc, bpp, slice_width, slice_height, pps->dsc_version_minor);
++ dsc_params->pps = *pps;
++ dsc_params->pps.initial_scale_value = 8 * rc.rc_model_size / (rc.rc_model_size - rc.initial_fullness_offset);
++
++ copy_pps_fields(&dsc_cfg, &dsc_params->pps);
++ copy_rc_to_cfg(&dsc_cfg, &rc);
++
++ dsc_cfg.mux_word_size = dsc_params->pps.bits_per_component <= 10 ? 48 : 64;
++
++ ret = drm_dsc_compute_rc_parameters(&dsc_cfg);
++
++ copy_pps_fields(&dsc_params->pps, &dsc_cfg);
++ dsc_params->rc_buffer_model_size = dsc_cfg.rc_bits;
++ return ret;
++}
++
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
+index 8dca3b7700e5..0a094d7c9380 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
+@@ -43,7 +43,12 @@ enum dc_status {
+ DC_FAIL_BANDWIDTH_VALIDATE = 13, /* BW and Watermark validation */
+ DC_FAIL_SCALING = 14,
+ DC_FAIL_DP_LINK_TRAINING = 15,
++#ifdef CONFIG_DRM_AMD_DC_DCN2_0
++ DC_FAIL_DSC_VALIDATE = 16,
++ DC_NO_DSC_RESOURCE = 17,
++#endif
+ DC_FAIL_UNSUPPORTED_1 = 18,
++
+ DC_ERROR_UNEXPECTED = -1
+ };
+
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+index d31dc3fe8ce8..2d551a6848f5 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+@@ -179,6 +179,9 @@ struct resource_pool {
+ } gsl_groups;
+ #endif
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ struct display_stream_compressor *dscs[MAX_PIPES];
++#endif
+
+ unsigned int pipe_count;
+ unsigned int underlay_pipe_index;
+@@ -219,10 +222,16 @@ struct resource_pool {
+
+ struct dcn_fe_bandwidth {
+ int dppclk_khz;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ int dscclk_khz;
++#endif
+ };
+
+ struct stream_resource {
+ struct output_pixel_processor *opp;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ struct display_stream_compressor *dsc;
++#endif
+ struct timing_generator *tg;
+ struct stream_encoder *stream_enc;
+ struct audio *audio;
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+index a37255c757e0..6c822a69b35b 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+@@ -62,4 +62,10 @@ bool is_dp_active_dongle(const struct dc_link *link);
+
+ void dp_enable_mst_on_sink(struct dc_link *link, bool enable);
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++void dp_set_fec_ready(struct dc_link *link, bool ready);
++void dp_set_fec_enable(struct dc_link *link, bool enable);
++bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
++#endif
++
+ #endif /* __DC_LINK_DP_H__ */
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
+new file mode 100644
+index 000000000000..c905d020b59e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
+@@ -0,0 +1,101 @@
++/*
++ * Copyright 2017 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#ifndef __DAL_DSC_H__
++#define __DAL_DSC_H__
++
++#include "dc_dsc.h"
++#include "dc_hw_types.h"
++#include "dc_dp_types.h"
++
++/* Input parameters for configuring DSC from the outside of DSC */
++struct dsc_config {
++ uint32_t pic_width;
++ uint32_t pic_height;
++ enum dc_pixel_encoding pixel_encoding;
++ enum dc_color_depth color_depth; /* Bits per component */
++ struct dc_dsc_config dc_dsc_cfg;
++};
++
++
++/* Output parameters for configuring DSC-related part of OPTC */
++struct dsc_optc_config {
++ uint32_t slice_width; /* Slice width in pixels */
++ uint32_t bytes_per_pixel; /* Bytes per pixel in u3.28 format */
++ bool is_pixel_format_444; /* 'true' if pixel format is 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4)' */
++};
++
++
++struct dcn_dsc_state {
++ uint32_t dsc_clock_en;
++ uint32_t dsc_slice_width;
++ uint32_t dsc_bytes_per_pixel;
++};
++
++
++/* DSC encoder capabilities
++ * They differ from the DPCD DSC caps because they are based on AMD DSC encoder caps.
++ */
++union dsc_enc_slice_caps {
++ struct {
++ uint8_t NUM_SLICES_1 : 1;
++ uint8_t NUM_SLICES_2 : 1;
++ uint8_t NUM_SLICES_3 : 1; /* This one is not per DSC spec, but our encoder supports it */
++ uint8_t NUM_SLICES_4 : 1;
++ uint8_t NUM_SLICES_8 : 1;
++ } bits;
++ uint8_t raw;
++};
++
++struct dsc_enc_caps {
++ uint8_t dsc_version;
++ union dsc_enc_slice_caps slice_caps;
++ int32_t lb_bit_depth;
++ bool is_block_pred_supported;
++ union dsc_color_formats color_formats;
++ union dsc_color_depth color_depth;
++ int32_t max_total_throughput_mps; /* Maximum total throughput with all the slices combined */
++ int32_t max_slice_width;
++ uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */
++};
++
++struct display_stream_compressor {
++ const struct dsc_funcs *funcs;
++ struct dc_context *ctx;
++ int inst;
++};
++
++struct dsc_funcs {
++ void (*dsc_get_enc_caps)(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz);
++ void (*dsc_read_state)(struct display_stream_compressor *dsc, struct dcn_dsc_state *s);
++ bool (*dsc_validate_stream)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg);
++ void (*dsc_set_config)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
++ struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps);
++ void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe);
++ void (*dsc_disable)(struct display_stream_compressor *dsc);
++};
++
++#endif
++#endif
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+index 1ff6a841fdd2..8759ec03aede 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+@@ -194,6 +194,13 @@ enum opp_regamma {
+ OPP_REGAMMA_USER
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++enum optc_dsc_mode {
++ OPTC_DSC_DISABLED = 0,
++ OPTC_DSC_ENABLED_444 = 1, /* 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4) */
++ OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED = 2 /* Native 4:2:2 or 4:2:0 */
++};
++#endif
+
+ struct dc_bias_and_scale {
+ uint16_t scale_red;
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+index 46de4a00f61b..e5e8640a9ef3 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+@@ -118,8 +118,21 @@ struct link_encoder {
+ #endif
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++struct link_enc_state {
++
++ uint32_t dphy_fec_en;
++ uint32_t dphy_fec_ready_shadow;
++ uint32_t dphy_fec_active_status;
++
++};
++#endif
+
+ struct link_encoder_funcs {
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ void (*read_state)(
++ struct link_encoder *enc, struct link_enc_state *s);
++#endif
+ bool (*validate_output_with_stream)(
+ struct link_encoder *enc, const struct dc_stream_state *stream);
+ void (*hw_init)(struct link_encoder *enc);
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+index f84ce4de53ca..d8418c27fd35 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+@@ -109,8 +109,22 @@ struct stream_encoder {
+ enum engine_id id;
+ };
+
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++struct enc_state {
++ uint32_t dsc_mode; // DISABLED 0; 1 or 2 indicate enabled state.
++ uint32_t dsc_slice_width;
++ uint32_t sec_gsp7_line_num;
++ uint32_t vbid6_line_reference;
++ uint32_t vbid6_line_num;
++ uint32_t sec_gsp7_enable;
++ uint32_t sec_stream_enable;
++};
++#endif
+
+ struct stream_encoder_funcs {
++ #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s);
++ #endif
+ void (*dp_set_stream_attribute)(
+ struct stream_encoder *enc,
+ struct dc_crtc_timing *crtc_timing,
+@@ -198,6 +212,14 @@ struct stream_encoder_funcs {
+ int tg_inst);
+
+ #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ void (*dp_set_dsc_config)(
++ struct stream_encoder *enc,
++ enum optc_dsc_mode dsc_mode,
++ uint32_t dsc_bytes_per_pixel,
++ uint32_t dsc_slice_width,
++ uint8_t *dsc_packed_pps);
++#endif
+
+ void (*set_dynamic_metadata)(struct stream_encoder *enc,
+ bool enable,
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+index e8e521102adb..eced6ec05899 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+@@ -258,6 +258,12 @@ struct timing_generator_funcs {
+ void (*set_vtg_params)(struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing);
+ #ifdef CONFIG_DRM_AMD_DC_DCN2_0
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ void (*set_dsc_config)(struct timing_generator *optc,
++ enum optc_dsc_mode dsc_mode,
++ uint32_t dsc_bytes_per_pixel,
++ uint32_t dsc_slice_width);
++#endif
+ void (*set_odm_bypass)(struct timing_generator *tg, const struct dc_crtc_timing *dc_crtc_timing);
+ void (*set_odm_combine)(struct timing_generator *tg, int combine_opp_id, int mpcc_hactive);
+ void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params);
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+index 60fa4697dc70..47f81072d7e9 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+@@ -46,6 +46,9 @@ struct resource_caps {
+ int num_ddc;
+ #ifdef CONFIG_DRM_AMD_DC_DCN2_0
+ int num_vmid;
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ int num_dsc;
++#endif
+ #endif
+ };
+
+diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c
+index 16586e434b3d..768bc8c75b6a 100644
+--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c
+@@ -76,10 +76,20 @@ static void virtual_audio_mute_control(
+ bool mute) {}
+
+ #ifdef CONFIG_DRM_AMD_DC_DCN2_0
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++static void virtual_enc_dp_set_odm_combine(
++ struct stream_encoder *enc,
++ bool odm_combine)
++{}
++#endif
+ #endif
+
+ static const struct stream_encoder_funcs virtual_str_enc_funcs = {
+ #ifdef CONFIG_DRM_AMD_DC_DCN2_0
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ .dp_set_odm_combine =
++ virtual_enc_dp_set_odm_combine,
++#endif
+ #endif
+ .dp_set_stream_attribute =
+ virtual_stream_encoder_dp_set_stream_attribute,
+diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h
+index d96550d6434d..22ba83f228cf 100644
+--- a/drivers/gpu/drm/amd/display/include/logger_types.h
++++ b/drivers/gpu/drm/amd/display/include/logger_types.h
+@@ -63,6 +63,9 @@
+ #define DC_LOG_IF_TRACE(...) pr_debug("[IF_TRACE]:"__VA_ARGS__)
+ #define DC_LOG_PERF_TRACE(...) DRM_DEBUG_KMS(__VA_ARGS__)
+ #define DC_LOG_RETIMER_REDRIVER(...) DRM_DEBUG_KMS(__VA_ARGS__)
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++#define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__)
++#endif
+
+ struct dal_logger;
+
+@@ -107,6 +110,9 @@ enum dc_log_type {
+ LOG_PERF_TRACE,
+ LOG_DISPLAYSTATS,
+ LOG_HDMI_RETIMER_REDRIVER,
++#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
++ LOG_DSC,
++#endif
+ LOG_SECTION_TOTAL_COUNT
+ };
+
+--
+2.17.1
+