summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2019-02-25 13:26:34 -0500
committerAlex Deucher <alexander.deucher@amd.com>2019-06-22 09:34:07 -0500
commit97bda0322b8a91aa8d534763e709571b2334e585 (patch)
tree9e572c249b54a91c58a771d5eeef5ffc51cfe587 /drivers/gpu/drm/amd
parentb4f199c7b00c87183f10c0a8f635f26ba2ede3eb (diff)
drm/amd/display: Add DSC support for Navi (v2)
Add support for DCN2 DSC (Display Stream Compression) HW Blocks: +--------++------+ +----------+ | HUBBUB || HUBP | <-- | MMHUBBUB | +--------++------+ +----------+ | ^ v | +--------+ +--------+ | DPP | | DWB | +--------+ +--------+ | v ^ +--------+ | | MPC | | +--------+ | | | v | +-------+ +-------+ | | OPP | <--> | DSC | | +-------+ +-------+ | | | v | +--------+ / | OPTC | -------------- +--------+ | v +--------+ +--------+ | DIO | | DCCG | +--------+ +--------+ v2: rebase (Alex) Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile3
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c51
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c153
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c145
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dsc.h61
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h69
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c58
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/Makefile4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c688
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h573
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c93
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c38
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c184
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c168
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/Makefile13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c899
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c382
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c243
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h54
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h706
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c258
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h85
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c147
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_status.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h101
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h22
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c10
-rw-r--r--drivers/gpu/drm/amd/display/include/logger_types.h6
48 files changed, 5440 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index df951cbb4c6c..27afdb5db626 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -25,6 +25,16 @@ config DRM_AMD_DC_DCN2_0
Choose this option if you want to have
Navi support for display engine
+config DRM_AMD_DC_DSC_SUPPORT
+ bool "DSC support"
+ default n
+ depends on DRM_AMD_DC && X86
+ depends on DRM_AMD_DC_DCN1_0
+ depends on DRM_AMD_DC_DCN2_0
+ help
+ Choose this option if you want to have
+ Dynamic Stream Compression support
+
config DEBUG_KERNEL_DC
bool "Enable kgdb break in DC"
depends on DRM_AMD_DC
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index e6cd67342df8..7cf0573ab25f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -542,6 +542,16 @@ bool dm_helpers_submit_i2c(
return result;
}
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+bool dm_helpers_dp_write_dsc_enable(
+ struct dc_context *ctx,
+ const struct dc_stream_state *stream,
+ bool enable
+)
+{
+ return false;
+}
+#endif
bool dm_helpers_is_dp_sink_present(struct dc_link *link)
{
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 9c0a755414de..00eaa69ba53d 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -30,6 +30,9 @@ DC_LIBS += dcn20
endif
+ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+DC_LIBS += dsc
+endif
ifdef CONFIG_DRM_AMD_DC_DCN1_0
DC_LIBS += dcn10 dml
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 052d3c8c6b73..68eddcc0fbcc 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -56,6 +56,10 @@
#include "dc_link_dp.h"
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#include "dsc.h"
+#endif
+
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#include "vm_helper.h"
#endif
@@ -1730,6 +1734,23 @@ static void commit_planes_do_stream_update(struct dc *dc,
#endif
}
+#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
+ if (stream_update->dsc_config && dc->hwss.pipe_control_lock_global) {
+ if (stream_update->dsc_config->num_slices_h &&
+ stream_update->dsc_config->num_slices_v) {
+ /* dsc enable */
+ dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true);
+ dp_set_dsc_enable(pipe_ctx, true);
+ dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false);
+ } else {
+ /* dsc disable */
+ dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true);
+ dp_set_dsc_enable(pipe_ctx, false);
+ dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false);
+ }
+
+ }
+#endif
/* Full fe update*/
if (update_type == UPDATE_TYPE_FAST)
continue;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index af22ff050e6f..1af06637fdda 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -1508,6 +1508,9 @@ static enum dc_status enable_link_dp(
if (link_settings.link_rate == LINK_RATE_LOW)
skip_video_pattern = false;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ dp_set_fec_ready(link, true);
+#endif
if (perform_link_training_with_retries(
link,
@@ -1520,6 +1523,9 @@ static enum dc_status enable_link_dp(
else
status = DC_FAIL_DP_LINK_TRAINING;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ dp_set_fec_enable(link, true);
+#endif
return status;
}
@@ -2142,6 +2148,14 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
dp_disable_link_phy(link, signal);
else
dp_disable_link_phy_mst(link, signal);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+
+ if (dc_is_dp_sst_signal(signal) ||
+ link->mst_stream_alloc_table.stream_count == 0) {
+ dp_set_fec_enable(link, false);
+ dp_set_fec_ready(link, false);
+ }
+#endif
} else
link->link_enc->funcs->disable_output(link->link_enc, signal);
@@ -2376,6 +2390,11 @@ static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream)
&stream->link->cur_link_settings);
link_rate_in_mbytes_per_sec /= 8000; /* Kbits to MBytes */
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (stream->link->fec_state != dc_link_fec_not_ready)
+ link_rate_in_mbytes_per_sec = (link_rate_in_mbytes_per_sec * 970)/1000;
+#endif
+
mbytes_per_sec = dc_fixpt_from_int(link_rate_in_mbytes_per_sec);
return dc_fixpt_div_int(mbytes_per_sec, 54);
@@ -2738,12 +2757,30 @@ void core_link_enable_stream(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
allocate_mst_payload(pipe_ctx);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (pipe_ctx->stream->timing.flags.DSC &&
+ (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))) {
+ dp_set_dsc_enable(pipe_ctx, true);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(
+ pipe_ctx->stream_res.tg,
+ CRTC_STATE_VBLANK);
+ }
+#endif
core_dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->link->cur_link_settings);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
enable_stream_features(pipe_ctx);
}
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ else { // if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment))
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ dp_set_dsc_enable(pipe_ctx, true);
+
+ }
+#endif
}
void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
@@ -2784,6 +2821,12 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
core_dc->hwss.disable_stream(pipe_ctx, option);
disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (pipe_ctx->stream->timing.flags.DSC &&
+ dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ dp_set_dsc_enable(pipe_ctx, false);
+ }
+#endif
}
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
@@ -2851,6 +2894,14 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
uint32_t bits_per_channel = 0;
uint32_t kbps;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (timing->flags.DSC) {
+ kbps = (timing->pix_clk_100hz * timing->dsc_cfg.bits_per_pixel);
+ kbps = kbps / 160 + ((kbps % 160) ? 1 : 0);
+ return kbps;
+ }
+#endif
+
switch (timing->display_color_depth) {
case COLOR_DEPTH_666:
bits_per_channel = 6;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 4d0c2bb32dc5..effc36745671 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -4,6 +4,9 @@
#include "dc_link_dp.h"
#include "dm_helpers.h"
#include "opp.h"
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#include "dsc.h"
+#endif
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#include "resource.h"
#endif
@@ -2379,6 +2382,10 @@ static bool retrieve_link_cap(struct dc_link *link)
uint32_t read_dpcd_retry_cnt = 3;
int i;
struct dp_sink_hw_fw_revision dp_hw_fw_revision;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ uint8_t dsc_data[16];
+ struct dsc_dec_dpcd_caps *dsc_caps;
+#endif
memset(dpcd_data, '\0', sizeof(dpcd_data));
memset(&down_strm_port_count,
@@ -2550,6 +2557,90 @@ static bool retrieve_link_cap(struct dc_link *link)
dp_hw_fw_revision.ieee_fw_rev,
sizeof(dp_hw_fw_revision.ieee_fw_rev));
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ dsc_caps = &link->dpcd_caps.dsc_sink_caps;
+ memset(dsc_caps, '\0', sizeof(*dsc_caps));
+ memset(&link->dpcd_caps.dsc_sink_caps, '\0',
+ sizeof(link->dpcd_caps.dsc_sink_caps));
+ memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+ /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DSC_SUPPORT,
+ dsc_data,
+ sizeof(dsc_data));
+ if (status == DC_OK) {
+ DC_LOG_DSC("DSC capability read at link %d:",
+ link->link_index);
+ DC_LOG_DSC("\t%02x %02x %02x %02x",
+ dsc_data[0], dsc_data[1],
+ dsc_data[2], dsc_data[3]);
+ DC_LOG_DSC("\t%02x %02x %02x %02x",
+ dsc_data[4], dsc_data[5],
+ dsc_data[6], dsc_data[7]);
+ DC_LOG_DSC("\t%02x %02x %02x %02x",
+ dsc_data[8], dsc_data[9],
+ dsc_data[10], dsc_data[11]);
+ DC_LOG_DSC("\t%02x %02x %02x %02x",
+ dsc_data[12], dsc_data[13],
+ dsc_data[14], dsc_data[15]);
+ } else {
+ dm_error("%s: Read DSC dpcd data failed.\n", __func__);
+ return false;
+ }
+
+ if (dc_dsc_parse_dsc_dpcd(dsc_data,
+ dsc_caps)) {
+ DC_LOG_DSC("DSC capability parsed at link %d:",
+ link->link_index);
+ DC_LOG_DSC("\tis_dsc_supported:\t%d",
+ dsc_caps->is_dsc_supported);
+ DC_LOG_DSC("\tdsc_version:\t%d", dsc_caps->dsc_version);
+ DC_LOG_DSC("\trc_buffer_size:\t%d",
+ dsc_caps->rc_buffer_size);
+ DC_LOG_DSC("\tslice_caps1:\t0x%x20",
+ dsc_caps->slice_caps1.raw);
+ DC_LOG_DSC("\tslice_caps2:\t0x%x20",
+ dsc_caps->slice_caps2.raw);
+ DC_LOG_DSC("\tlb_bit_depth:\t%d",
+ dsc_caps->lb_bit_depth);
+ DC_LOG_DSC("\tis_block_pred_supported:\t%d",
+ dsc_caps->is_block_pred_supported);
+ DC_LOG_DSC("\tedp_max_bits_per_pixel:\t%d",
+ dsc_caps->edp_max_bits_per_pixel);
+ DC_LOG_DSC("\tcolor_formats:\t%d",
+ dsc_caps->color_formats.raw);
+ DC_LOG_DSC("\tcolor_depth:\t%d",
+ dsc_caps->color_depth.raw);
+ DC_LOG_DSC("\tthroughput_mode_0_mps:\t%d",
+ dsc_caps->throughput_mode_0_mps);
+ DC_LOG_DSC("\tthroughput_mode_1_mps:\t%d",
+ dsc_caps->throughput_mode_1_mps);
+ DC_LOG_DSC("\tmax_slice_width:\t%d",
+ dsc_caps->max_slice_width);
+ DC_LOG_DSC("\tbpp_increment_div:\t%d",
+ dsc_caps->bpp_increment_div);
+ } else {
+ /* Some sinks return bogus DSC DPCD data
+ * when they don't support DSC.
+ */
+ dm_error("%s: DSC DPCD data doesn't make sense. "
+ "DSC will be disabled.\n", __func__);
+ memset(&link->dpcd_caps.dsc_sink_caps, '\0',
+ sizeof(link->dpcd_caps.dsc_sink_caps));
+ }
+
+ status = core_link_read_dpcd(
+ link,
+ DP_FEC_CAPABILITY,
+ &link->dpcd_caps.fec_cap.raw,
+ sizeof(link->dpcd_caps.fec_cap.raw));
+ if (status != DC_OK)
+ dm_error("%s: Read FEC dpcd register failed.\n",
+ __func__);
+ }
+#endif
/* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
@@ -2964,4 +3055,66 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
}
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+void dp_set_fec_ready(struct dc_link *link, bool ready)
+{
+ /* FEC has to be "set ready" before the link training.
+ * The policy is to always train with FEC
+ * if the sink supports it and leave it enabled on link.
+ * If FEC is not supported, disable it.
+ */
+ struct link_encoder *link_enc = link->link_enc;
+ uint8_t fec_config = 0;
+
+ if (link->dc->debug.disable_fec ||
+ IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment))
+ return;
+
+ if (link_enc->funcs->fec_set_ready &&
+ link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
+ if (link->fec_state == dc_link_fec_not_ready && ready) {
+ fec_config = 1;
+ if (core_link_write_dpcd(link,
+ DP_FEC_CONFIGURATION,
+ &fec_config,
+ sizeof(fec_config)) == DC_OK) {
+ link_enc->funcs->fec_set_ready(link_enc, true);
+ link->fec_state = dc_link_fec_ready;
+ } else {
+ dm_error("dpcd write failed to set fec_ready");
+ }
+ } else if (link->fec_state == dc_link_fec_ready && !ready) {
+ fec_config = 0;
+ core_link_write_dpcd(link,
+ DP_FEC_CONFIGURATION,
+ &fec_config,
+ sizeof(fec_config));
+ link->link_enc->funcs->fec_set_ready(
+ link->link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+ }
+ }
+}
+
+void dp_set_fec_enable(struct dc_link *link, bool enable)
+{
+ struct link_encoder *link_enc = link->link_enc;
+
+ if (link->dc->debug.disable_fec ||
+ IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment))
+ return;
+
+ if (link_enc->funcs->fec_set_enable &&
+ link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
+ if (link->fec_state == dc_link_fec_ready && enable) {
+ msleep(1);
+ link_enc->funcs->fec_set_enable(link_enc, true);
+ link->fec_state = dc_link_fec_enabled;
+ } else if (link->fec_state == dc_link_fec_enabled && !enable) {
+ link_enc->funcs->fec_set_enable(link_enc, false);
+ link->fec_state = dc_link_fec_ready;
+ }
+ }
+}
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
index b0dea759cd86..8b22af9085e4 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -12,6 +12,12 @@
#include "dc_link_ddc.h"
#include "dm_helpers.h"
#include "dpcd_defs.h"
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#include "dsc.h"
+#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
+#include "resource.h"
+#endif
enum dc_status core_link_read_dpcd(
struct dc_link *link,
@@ -360,3 +366,142 @@ void dp_retrain_link_dp_test(struct dc_link *link,
}
}
}
+
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#define DC_LOGGER \
+ dsc->ctx->logger
+static void dsc_optc_config_log(struct display_stream_compressor *dsc,
+ struct dsc_optc_config *config)
+{
+ DC_LOG_DSC("Setting optc DSC config at DSC inst %d", dsc->inst);
+ DC_LOG_DSC("\n\tbytes_per_pixel %d\n\tis_pixel_format_444 %d\n\tslice_width %d",
+ config->bytes_per_pixel,
+ config->is_pixel_format_444, config->slice_width);
+}
+
+static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc *core_dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ bool result = false;
+
+ if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment))
+ result = true;
+ else
+ result = dm_helpers_dp_write_dsc_enable(core_dc->ctx, stream, enable);
+ return result;
+}
+
+/* This has to be done after DSC was enabled on RX first, i.e. after dp_enable_dsc_on_rx() had been called
+ */
+static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *core_dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+
+ if (enable) {
+ /* TODO proper function */
+ struct dsc_config dsc_cfg;
+ struct dsc_optc_config dsc_optc_cfg;
+ enum optc_dsc_mode optc_dsc_mode;
+ uint8_t dsc_packed_pps[128];
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps[0]);
+ if (odm_pipe) {
+ struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc;
+ uint8_t dsc_packed_pps_odm[128];
+
+ dsc_cfg.pic_width /= 2;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= 2;
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
+ bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
+ bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst);
+ }
+ dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+
+ optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ /* Enable DSC in encoder */
+ if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width,
+ &dsc_packed_pps[0]);
+
+ /* Enable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+ } else {
+ /* disable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+ pipe_ctx->stream_res.tg,
+ OPTC_DSC_DISABLED, 0, 0);
+
+ /* disable DSC in stream encoder */
+ if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+ pipe_ctx->stream_res.stream_enc,
+ OPTC_DSC_DISABLED, 0, 0, NULL);
+ }
+
+ /* disable DSC block */
+ pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+ if (odm_pipe)
+ odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ }
+}
+
+bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ bool result = false;
+
+ if (!dsc)
+ goto out;
+
+ if (enable && stream->is_dsc_enabled) {
+ /* update dsc stream */
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ stream->is_dsc_enabled = true;
+ result = true;
+ } else if (enable && !stream->is_dsc_enabled) {
+ /* enable dsc on non dsc stream */
+ if (dp_set_dsc_on_rx(pipe_ctx, true)) {
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ stream->is_dsc_enabled = true;
+ result = true;
+ } else {
+ stream->is_dsc_enabled = false;
+ result = false;
+ }
+ } else if (!enable && stream->is_dsc_enabled) {
+ /* disable dsc on dsc stream */
+ dp_set_dsc_on_rx(pipe_ctx, false);
+ dp_set_dsc_on_stream(pipe_ctx, false);
+ stream->is_dsc_enabled = false;
+ result = true;
+ } else {
+ /* disable dsc on non dsc stream */
+ result = true;
+ }
+out:
+ return result;
+}
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index de50d778e4b0..3787398f6d80 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -105,6 +105,16 @@ static void construct(struct dc_stream_state *stream,
/* EDID CAP translation for HDMI 2.0 */
stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg));
+ stream->timing.dsc_cfg.num_slices_h = 0;
+ stream->timing.dsc_cfg.num_slices_v = 0;
+ stream->timing.dsc_cfg.bits_per_pixel = 128;
+ stream->timing.dsc_cfg.block_pred_enable = 1;
+ stream->timing.dsc_cfg.linebuf_depth = 9;
+ stream->timing.dsc_cfg.version_minor = 2;
+ stream->timing.dsc_cfg.ycbcr422_simple = 0;
+#endif
update_stream_signal(stream, dc_sink_data);
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 676f30e647b6..139ea7354910 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -331,6 +331,9 @@ struct dc_debug_options {
bool disable_dfs_bypass;
bool disable_dpp_power_gate;
bool disable_hubp_power_gate;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool disable_dsc_power_gate;
+#endif
bool disable_pplib_wm_range;
enum wm_report_mode pplib_wm_report_mode;
unsigned int min_disp_clk_khz;
@@ -363,6 +366,9 @@ struct dc_debug_options {
unsigned int force_fclk_khz;
bool disable_tri_buf;
struct dc_bw_validation_profile bw_val_profile;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool disable_fec;
+#endif
};
struct dc_debug_data {
@@ -894,6 +900,10 @@ struct dpcd_caps {
bool panel_mode_edp;
bool dpcd_display_control_capable;
bool ext_receiver_cap_field_present;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ union fec_capability fec_cap;
+ struct dsc_dec_dpcd_caps dsc_sink_caps;
+#endif
};
#include "dc_link.h"
@@ -928,6 +938,14 @@ struct dc_sink {
struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX];
bool converter_disable_audio;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ struct dc_sink_dsc_caps {
+ // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology),
+ // 'false' if they are sink's DSC caps
+ bool is_virtual_dpcd_dsc;
+ struct dsc_dec_dpcd_caps dsc_dec_caps;
+ } sink_dsc_caps;
+#endif
/* private to DC core */
struct dc_link *link;
@@ -986,4 +1004,10 @@ unsigned int dc_get_target_backlight_pwm(struct dc *dc);
bool dc_is_dmcu_initialized(struct dc *dc);
+#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT)
+/*******************************************************************************
+ * DSC Interfaces
+ ******************************************************************************/
+#include "dc_dsc.h"
+#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 01793aa3e093..b7e2c6f767aa 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -553,6 +553,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 {
@@ -706,4 +709,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 dfa235aeed89..8c6d99c61f35 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
@@ -49,6 +49,9 @@
#include "clk_mgr.h"
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+#include "dsc.h"
+#endif
#define DC_LOGGER_INIT(logger)
@@ -347,6 +350,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 e4b850a2d31f..b3fc71648d16 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -1507,10 +1507,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
};