diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch | 6344 |
1 files changed, 6344 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/2456-drm-amd-display-Add-DSC-support-for-Navi-v2.patch b/common/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/common/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 + |