drm/amd/display: Add DSC support for Navi (v2)
authorHarry Wentland <harry.wentland@amd.com>
Mon, 25 Feb 2019 18:26:34 +0000 (13:26 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Sat, 22 Jun 2019 14:34:07 +0000 (09:34 -0500)
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>
48 files changed:
drivers/gpu/drm/amd/display/Kconfig
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/display/dc/Makefile
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/dc_dsc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn20/Makefile
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dm_helpers.h
drivers/gpu/drm/amd/display/dc/dsc/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/dsc_helpers.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/core_status.h
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
drivers/gpu/drm/amd/display/dc/inc/resource.h
drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c
drivers/gpu/drm/amd/display/include/logger_types.h

index df951cbb4c6c4d9d1c6409d7806cc7edfc8b1c10..27afdb5db626d184c1e7a37d4afac05020bbc3e0 100644 (file)
@@ -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
index e6cd67342df814e315a23bca5e3e5a329031eff5..7cf0573ab25fc62ddaf5ff0ac925e26e2e5e77a2 100644 (file)
@@ -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)
 {
index 9c0a755414def31e665326c72984d3b0933388a0..00eaa69ba53d8dab7b0d2680d99d360e699c2eef 100644 (file)
@@ -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
index 052d3c8c6b732caa0c6c6473ac343fdd125a56a5..68eddcc0fbccfcf32fe7a69dc16acd8dc7e48ba5 100644 (file)
 
 #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;
index af22ff050e6fde93828a75878b0b2eb55a38639a..1af06637fdda10ce5c29c2e37f8e3d555da1fe40 100644 (file)
@@ -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;
index 4d0c2bb32dc5eda43bff3b661f6f18bfe99b1374..effc36745671298e3d346a2655766f76d254baa3 100644 (file)
@@ -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
 
index b0dea759cd8600992a854ee4585398f85b1cb7a1..8b22af9085e42711921237738e5c3e7fb6e24a7d 100644 (file)
 #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
+
index de50d778e4b072cd4c1329ca6f9a2aff7c6d570a..3787398f6d80782fe7a5ece1a76337921a2add2b 100644 (file)
@@ -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);
 
index 676f30e647b612c4a6032ebbccb273d86288d3e4..139ea7354910d5357a1a0df2bccf17fab13c5f93 100644 (file)
@@ -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_ */
index 11c68a39926797b9211c499526f3e08a78a0a29d..6892bf80c9e06f0441c060f033b95ca99709ddf2 100644 (file)
@@ -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 (file)
index 0000000..c3a277c
--- /dev/null
@@ -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
index 6a9670de38f3a564473547786e2b0a48a43c1be4..ea7a1c9efca8aea2bf9edf6cb5489981635e33e1 100644 (file)
@@ -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 */
index 094009127e25337ac72e4e74f4bc2f0ba22e6ef9..6f0b80111e58c298e69f624d265b146d7585d2d5 100644 (file)
 #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);
index 929f155eaae724e410564dd12f0743a2c10f41c1..0a83cd36d506277fd782a00d6679c7110ec2de11 100644 (file)
@@ -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(
index 01793aa3e093415562d75ac3083c1746311afe87..b7e2c6f767aa99ef4a7752bb5cab3af370398526 100644 (file)
@@ -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_ */
index dfa235aeed89f4c6fbbaf9015b23e7f250de1c35..8c6d99c61f353c75e8cd94eea8b6393775282a76 100644 (file)
@@ -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",
index e4b850a2d31f5cf64f8b67f31d465829fe8294b7..b3fc71648d1654defb09d8e065279cb17c216f3c 100644 (file)
@@ -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;
 }
 
index 23bec3912c3ce18060784b64149c27bb6b569237..a6299f0d6b226b81acd4d89a3ef94912cb12deaf 100644 (file)
@@ -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 (file)
index 0000000..d17accc
--- /dev/null
@@ -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 (file)
index 0000000..5cbb9df
--- /dev/null
@@ -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
index 3d5eb20ea9ba0424cb420184bff286e1407ca77b..1fd89cc218a5260b8d24b4c25b5f4c96c202e03d 100644 (file)
@@ -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)
index 290ebaacbabe936e3acae61a6c3bfbd25594f03c..6f7af235dd7979a4768bb183d37ef1981b6a7408 100644 (file)
@@ -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,
index c677557790790068e6d95ad20e3c96b111c7cc25..401fdea77262d671ad9b96816a5552eb9fa7b282 100644 (file)
@@ -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,
index 72d72c3a35eefa90807ca45ca7ce8131cd88fbbe..875b48e450f84cda4742aec16e20c20ad6acb2f3 100644 (file)
@@ -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,
index fe851049aa9bc943759daf32dfe4a4e8b6199b0a..b936a4da15832458fafa550c390d79bd47e973e5 100644 (file)
@@ -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);
index af4e2447a5da80094eade58800a45113896f964d..d0c279ab0af14ed51b404ca87c118055668830a1 100644 (file)
 #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) ?
index c38c85c8e3b9f27dd0e2912ff18a16215f1df160..d99b1fc8f2df2b4e87eaace6990e6dc9338dabee 100644 (file)
@@ -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,
 };
 
index ccbfe9680d275a5ddea6de567526d71928d701bd..b6b4333737f21828ae1382226c504d2fe392ff99 100644 (file)
@@ -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 (file)
index 0000000..c5d5b94
--- /dev/null
@@ -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 (file)
index 0000000..4ffcc28
--- /dev/null
@@ -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 (file)
index 0000000..6708976
--- /dev/null
@@ -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 (file)
index 0000000..0ecd506
--- /dev/null
@@ -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 (file)
index 0000000..020ad8f
--- /dev/null
@@ -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 (file)
index 0000000..f66d006
--- /dev/null
@@ -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 (file)
index 0000000..ca51e83
--- /dev/null
@@ -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 (file)
index 0000000..f1d6e79
--- /dev/null
@@ -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 (file)
index 0000000..73172fd
--- /dev/null
@@ -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
index 8dca3b7700e56540749e6db4d347e09a4f1328db..0a094d7c93805049284e9e9146737311a92cc7d3 100644 (file)
@@ -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
 };
 
index d31dc3fe8ce86e4279758729e317f18442e58258..2d551a6848f516066491dfed365a25290719cc02 100644 (file)
@@ -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;
index a37255c757e0ce11f33e9803b63cc26c017e631f..6c822a69b35bb9b8889e7abae52fa4d870d76081 100644 (file)
@@ -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 (file)
index 0000000..c905d02
--- /dev/null
@@ -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
index 1ff6a841fdd291b7f42b470ccbca690cbcb2fd32..8759ec03aedec0e63047d34eab9c966c3f9fe6e7 100644 (file)
@@ -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;
index 46de4a00f61b1007bcd179662aa62cb542dd3d27..e5e8640a9ef3ba657dd222b8642108a1650151a6 100644 (file)
@@ -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);
index f84ce4de53ca21a2c0b24d200e55126c2d3ebfb6..d8418c27fd358311e4fe0d4fcc6c2aea1c01499f 100644 (file)
@@ -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,
index e8e521102adb80ec8a5f33edc32e5ca0c35d28ad..eced6ec0589988446c13e427fc64d50dc444c878 100644 (file)
@@ -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);
index 60fa4697dc70424ab51a5f4a6f951a4792062c5c..47f81072d7e96783c79a51238eb2f9a0a05d90ff 100644 (file)
@@ -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
 };
 
index 16586e434b3d5a660da46189ac5f7f8a297c9afe..768bc8c75b6abd6d5caf94e484336d865827eb5b 100644 (file)
@@ -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,
index d96550d6434d5d6f5a5884e8db1530a26c2e8deb..22ba83f228cf5b523407208687a290b53857c2b2 100644 (file)
@@ -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
 };