diff --git a/msm/Makefile b/msm/Makefile index 2717193bd8..41f1c01894 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -72,6 +72,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_ds.o \ sde/sde_fence.o \ sde/sde_hw_qdss.o \ + sde_dsc_helper.o \ msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o \ diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index e4248297fd..062a8e8580 100644 --- a/msm/dp/dp_ctrl.c +++ b/msm/dp/dp_ctrl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include @@ -1003,7 +1003,7 @@ static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl, u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp; if (panel->pinfo.comp_info.comp_ratio) - bpp = panel->pinfo.comp_info.dsc_info.bpp; + bpp = DSC_BPP(panel->pinfo.comp_info.dsc_info.config); /* min_slot_cnt */ numerator = pclk * bpp * 64 * 1000; diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 2e158b396f..2288838300 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -2085,8 +2085,9 @@ static enum drm_mode_status dp_display_validate_mode( dp_display->convert_to_dp_mode(dp_display, panel, mode, &dp_mode); dsc_en = dp_mode.timing.comp_info.comp_ratio ? true : false; - mode_bpp = dsc_en ? dp_mode.timing.comp_info.dsc_info.bpp : - dp_mode.timing.bpp; + mode_bpp = dsc_en ? + DSC_BPP(dp_mode.timing.comp_info.dsc_info.config) + : dp_mode.timing.bpp; mode_rate_khz = mode->clock * mode_bpp; rate = drm_dp_bw_code_to_link_rate(dp->link->link_params.bw_code); diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index 578318fba4..cbbf5c4c5b 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ /* @@ -527,8 +527,9 @@ static int dp_mst_calc_pbn_mode(struct dp_display_mode *dp_mode) s64 pbn_fp; dsc_en = dp_mode->timing.comp_info.comp_ratio ? true : false; - bpp = dsc_en ? dp_mode->timing.comp_info.dsc_info.bpp : - dp_mode->timing.bpp; + bpp = dsc_en ? + DSC_BPP(dp_mode->timing.comp_info.dsc_info.config) + : dp_mode->timing.bpp; pbn = drm_dp_calc_pbn_mode(dp_mode->timing.pixel_clk_khz, bpp); pbn_fp = drm_fixp_from_fraction(pbn, 1); diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index dec4143d45..2b79572408 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include "dp_panel.h" #include #include #include "dp_debug.h" +#include +#include "sde_dsc_helper.h" #define DP_KHZ_TO_HZ 1000 #define DP_PANEL_DEFAULT_BPP 24 @@ -1062,68 +1064,6 @@ static void dp_panel_config_tr_unit(struct dp_panel *dp_panel) catalog->update_transfer_unit(catalog); } -enum dp_dsc_ratio_type { - DSC_8BPC_8BPP, - DSC_10BPC_8BPP, - DSC_12BPC_8BPP, - DSC_10BPC_10BPP, - DSC_RATIO_TYPE_MAX -}; - -static u32 dp_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, - 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; - -/* - * DSC 1.1 - * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type - */ -static char dp_dsc_rc_range_min_qp_1_1[][15] = { - {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13}, - {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, - {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21}, - {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, - }; - -/* - * DSC 1.1 SCR - * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type - */ -static char dp_dsc_rc_range_min_qp_1_1_scr1[][15] = { - {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, - {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, - {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, - {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, - }; - -/* - * DSC 1.1 - * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type - */ -static char dp_dsc_rc_range_max_qp_1_1[][15] = { - {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, - {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, - {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23}, - {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, - }; - -/* - * DSC 1.1 SCR - * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type - */ -static char dp_dsc_rc_range_max_qp_1_1_scr1[][15] = { - {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, - {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, - {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21}, - {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, - }; - -/* - * DSC 1.1 and DSC 1.1 SCR - * Rate control - bpg offset values - */ -static char dp_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, - -8, -10, -10, -12, -12, -12, -12}; - struct dp_dsc_dto_data { enum msm_display_compression_ratio comp_ratio; u32 org_bpp; /* bits */ @@ -1153,108 +1093,6 @@ static void _dp_panel_get_dto_m_n(enum msm_display_compression_ratio ratio, } } -static int dp_panel_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, - char *buf, int pps_id) -{ - char *bp = buf; - char data; - int i, bpp; - - *bp++ = (dsc->version & 0xff); /* pps0 */ - *bp++ = (pps_id & 0xff); /* pps1 */ - bp++; /* pps2, reserved */ - - data = dsc->line_buf_depth & 0x0f; - data |= ((dsc->bpc & 0xf) << 4); - *bp++ = data; /* pps3 */ - - bpp = dsc->bpp; - bpp <<= 4; /* 4 fraction bits */ - data = (bpp >> 8); - data &= 0x03; /* upper two bits */ - data |= ((dsc->block_pred_enable & 0x1) << 5); - data |= ((dsc->convert_rgb & 0x1) << 4); - data |= ((dsc->enable_422 & 0x1) << 3); - data |= ((dsc->vbr_enable & 0x1) << 2); - *bp++ = data; /* pps4 */ - *bp++ = (bpp & 0xff); /* pps5 */ - - *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ - *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ - *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ - *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ - - *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ - *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ - *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ - *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ - - *bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */ - *bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */ - - *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16*/ - *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ - - *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ - *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ - - bp++; /* pps20, reserved */ - - *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ - - *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ - *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ - - *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ - *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ - - bp++; /* pps26, reserved */ - - *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ - - *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ - *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ - *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ - *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ - - *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ - *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ - - *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ - *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ - - *bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */ - *bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */ - - *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ - *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ - - *bp++ = (dsc->edge_factor & 0x0f); /* pps40 */ - - *bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */ - *bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */ - - data = ((dsc->tgt_offset_hi & 0xf) << 4); - data |= (dsc->tgt_offset_lo & 0x0f); - *bp++ = data; /* pps43 */ - - for (i = 0; i < ARRAY_SIZE(dp_dsc_rc_buf_thresh); i++) - *bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */ - - for (i = 0; i < 15; i++) { /* pps58 - pps87 */ - data = (dsc->range_min_qp[i] & 0x1f); - data <<= 3; - data |= ((dsc->range_max_qp[i] >> 2) & 0x07); - *bp++ = data; - data = (dsc->range_max_qp[i] & 0x03); - data <<= 6; - data |= (dsc->range_bpg_offset[i] & 0x3f); - *bp++ = data; - } - - return 88; -} - static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel) { struct dp_panel_private *panel; @@ -1301,10 +1139,11 @@ static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc, unsigned int dto_n = 0, dto_d = 0, remainder; int ack_required, last_few_ack_required, accum_ack; int last_few_pclk, last_few_pclk_required; - int start, temp, line_width = dsc->pic_width/2; + int start, temp, line_width = dsc->config.pic_width/2; s64 temp1_fp, temp2_fp; - _dp_panel_get_dto_m_n(ratio, dsc->bpc * 3, &dto_n, &dto_d); + _dp_panel_get_dto_m_n(ratio, dsc->config.bits_per_component * 3, + &dto_n, &dto_d); ack_required = dsc->pclk_per_line; @@ -1383,9 +1222,8 @@ static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, enum msm_display_compression_ratio ratio, struct dp_display_mode *dp_mode) { - int slice_per_pkt, slice_per_intf, intf_width; - int bytes_in_slice, total_bytes_per_intf; - int comp_ratio; + int comp_ratio, intf_width; + int slice_per_pkt, slice_per_intf; s64 temp1_fp, temp2_fp; s64 numerator_fp, denominator_fp; s64 dsc_byte_count_fp; @@ -1393,21 +1231,12 @@ static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, intf_width = dp_mode->timing.h_active; if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || - (intf_width < dsc->slice_width)) + (intf_width < dsc->slice_width)) return; slice_per_pkt = dsc->slice_per_pkt; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); - - if (slice_per_pkt > slice_per_intf) - slice_per_pkt = 1; - - bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); - total_bytes_per_intf = bytes_in_slice * slice_per_intf; - - dsc->bytes_in_slice = bytes_in_slice; - dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; - dsc->pkt_per_line = slice_per_intf / slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, + dsc->config.slice_width); switch (ratio) { case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: @@ -1424,7 +1253,8 @@ static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, temp1_fp = drm_fixp_from_fraction(comp_ratio, 100); temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1); denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp); - numerator_fp = drm_fixp_from_fraction(intf_width * dsc->bpc * 3, 1); + numerator_fp = drm_fixp_from_fraction( + intf_width * dsc->config.bits_per_component * 3, 1); dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp); dsc_byte_count = drm_fixp2int_ceil(dsc_byte_count_fp); @@ -1445,169 +1275,6 @@ static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, _dp_panel_dsc_bw_overhead_calc(dp_panel, dsc, dp_mode, dsc_byte_count); } -static void dp_panel_dsc_populate_static_params( - struct msm_display_dsc_info *dsc, struct dp_panel *panel) -{ - int bpp, bpc; - int mux_words_size; - int groups_per_line, groups_total; - int min_rate_buffer_size; - int hrd_delay; - int pre_num_extra_mux_bits, num_extra_mux_bits; - int slice_bits; - int data; - int final_value, final_scale; - int ratio_index, mod_offset; - int line_buf_depth_raw, line_buf_depth; - - dsc->version = 0x11; - dsc->scr_rev = 0; - dsc->rc_model_size = 8192; - - if (dsc->version == 0x11 && dsc->scr_rev == 0x1) - dsc->first_line_bpg_offset = 15; - else - dsc->first_line_bpg_offset = 12; - - dsc->edge_factor = 6; - dsc->tgt_offset_hi = 3; - dsc->tgt_offset_lo = 3; - dsc->enable_422 = 0; - dsc->convert_rgb = 1; - dsc->vbr_enable = 0; - - dsc->buf_thresh = dp_dsc_rc_buf_thresh; - - bpp = dsc->bpp; - bpc = dsc->bpc; - - if (bpc == 12 && bpp == 8) - ratio_index = DSC_12BPC_8BPP; - else if (bpc == 10 && bpp == 8) - ratio_index = DSC_10BPC_8BPP; - else if (bpc == 10 && bpp == 10) - ratio_index = DSC_10BPC_10BPP; - else - ratio_index = DSC_8BPC_8BPP; - - if (dsc->version == 0x11 && dsc->scr_rev == 0x1) { - dsc->range_min_qp = - dp_dsc_rc_range_min_qp_1_1_scr1[ratio_index]; - dsc->range_max_qp = - dp_dsc_rc_range_max_qp_1_1_scr1[ratio_index]; - } else { - dsc->range_min_qp = dp_dsc_rc_range_min_qp_1_1[ratio_index]; - dsc->range_max_qp = dp_dsc_rc_range_max_qp_1_1[ratio_index]; - } - dsc->range_bpg_offset = dp_dsc_rc_range_bpg_offset; - - if (bpp == 8) { - dsc->initial_offset = 6144; - dsc->initial_xmit_delay = 512; - } else if (bpp == 10) { - dsc->initial_offset = 5632; - dsc->initial_xmit_delay = 410; - } else { - dsc->initial_offset = 2048; - dsc->initial_xmit_delay = 341; - } - - line_buf_depth_raw = panel->dsc_dpcd[5] & 0x0f; - line_buf_depth = (line_buf_depth_raw == 8) ? 8 : - (line_buf_depth_raw + 9); - dsc->line_buf_depth = min(line_buf_depth, dsc->bpc + 1); - - if (bpc == 8) { - dsc->input_10_bits = 0; - dsc->min_qp_flatness = 3; - dsc->max_qp_flatness = 12; - dsc->quant_incr_limit0 = 11; - dsc->quant_incr_limit1 = 11; - mux_words_size = 48; - } else if (bpc == 10) { /* 10bpc */ - dsc->input_10_bits = 1; - dsc->min_qp_flatness = 7; - dsc->max_qp_flatness = 16; - dsc->quant_incr_limit0 = 15; - dsc->quant_incr_limit1 = 15; - mux_words_size = 48; - } else { /* 12 bpc */ - dsc->input_10_bits = 0; - dsc->min_qp_flatness = 11; - dsc->max_qp_flatness = 20; - dsc->quant_incr_limit0 = 19; - dsc->quant_incr_limit1 = 19; - mux_words_size = 64; - } - - mod_offset = dsc->slice_width % 3; - switch (mod_offset) { - case 0: - dsc->slice_last_group_size = 2; - break; - case 1: - dsc->slice_last_group_size = 0; - break; - case 2: - dsc->slice_last_group_size = 1; - break; - default: - break; - } - - dsc->det_thresh_flatness = 2 << (bpc - 8); - - groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); - - dsc->chunk_size = dsc->slice_width * bpp / 8; - if ((dsc->slice_width * bpp) % 8) - dsc->chunk_size++; - - /* rbs-min */ - min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + - dsc->initial_xmit_delay * bpp + - groups_per_line * dsc->first_line_bpg_offset; - - hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); - - dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; - - dsc->initial_scale_value = 8 * dsc->rc_model_size / - (dsc->rc_model_size - dsc->initial_offset); - - slice_bits = 8 * dsc->chunk_size * dsc->slice_height; - - groups_total = groups_per_line * dsc->slice_height; - - data = dsc->first_line_bpg_offset * 2048; - - dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); - - pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2); - - num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - - ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); - - data = 2048 * (dsc->rc_model_size - dsc->initial_offset - + num_extra_mux_bits); - dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); - - data = dsc->initial_xmit_delay * bpp; - final_value = dsc->rc_model_size - data + num_extra_mux_bits; - - final_scale = 8 * dsc->rc_model_size / - (dsc->rc_model_size - final_value); - - dsc->final_offset = final_value; - - data = (final_scale - 9) * (dsc->nfl_bpg_offset + - dsc->slice_bpg_offset); - dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; - - dsc->scale_decrement_interval = groups_per_line / - (dsc->initial_scale_value - 8); -} - struct dp_dsc_slices_per_line { u32 min_ppr; u32 max_ppr; @@ -1711,6 +1378,10 @@ static int dp_panel_dsc_prepare_basic_params( u32 slice_caps_1; u32 slice_caps_2; + comp_info->dsc_info.config.dsc_version_major = 0x1; + comp_info->dsc_info.config.dsc_version_minor = 0x1; + comp_info->dsc_info.scr_rev = 0x0; + comp_info->dsc_info.slice_per_pkt = 0; for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) { rec = &slice_per_line_tbl[i]; @@ -1764,27 +1435,25 @@ static int dp_panel_dsc_prepare_basic_params( i++; } - comp_info->dsc_info.block_pred_enable = + comp_info->dsc_info.config.block_pred_enable = dp_panel->sink_dsc_caps.block_pred_en; - comp_info->dsc_info.vbr_enable = 0; - comp_info->dsc_info.enable_422 = 0; - comp_info->dsc_info.convert_rgb = 1; - comp_info->dsc_info.input_10_bits = 0; - comp_info->dsc_info.pic_width = dp_mode->timing.h_active; - comp_info->dsc_info.pic_height = dp_mode->timing.v_active; - comp_info->dsc_info.slice_width = slice_width; + comp_info->dsc_info.config.pic_width = dp_mode->timing.h_active; + comp_info->dsc_info.config.pic_height = dp_mode->timing.v_active; + comp_info->dsc_info.config.slice_width = slice_width; - if (comp_info->dsc_info.pic_height % 16 == 0) - comp_info->dsc_info.slice_height = 16; - else if (comp_info->dsc_info.pic_height % 12 == 0) - comp_info->dsc_info.slice_height = 12; + if (comp_info->dsc_info.config.pic_height % 16 == 0) + comp_info->dsc_info.config.slice_height = 16; + else if (comp_info->dsc_info.config.pic_height % 12 == 0) + comp_info->dsc_info.config.slice_height = 12; else - comp_info->dsc_info.slice_height = 15; + comp_info->dsc_info.config.slice_height = 15; - comp_info->dsc_info.bpc = dp_mode->timing.bpp / 3; - comp_info->dsc_info.bpp = comp_info->dsc_info.bpc; - comp_info->dsc_info.full_frame_slices = + comp_info->dsc_info.config.bits_per_component = + (dp_mode->timing.bpp / 3); + comp_info->dsc_info.config.bits_per_pixel = + comp_info->dsc_info.config.bits_per_component << 4; + comp_info->dsc_info.config.slice_count = DIV_ROUND_UP(dp_mode->timing.h_active, slice_width); comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; @@ -2508,7 +2177,7 @@ static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) struct dp_panel_info *pinfo; struct msm_compression_info *comp_info; struct dp_dsc_cfg_data *dsc; - int pps_len; + int rc; panel = container_of(dp_panel, struct dp_panel_private, dp_panel); @@ -2518,9 +2187,13 @@ static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) comp_info = &pinfo->comp_info; if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) { - pps_len = dp_panel_dsc_create_pps_buf_cmd(&comp_info->dsc_info, - dsc->pps, 0); - dsc->pps_len = pps_len; + rc = sde_dsc_create_pps_buf_cmd(&comp_info->dsc_info, + dsc->pps, 0, sizeof(dsc->pps)); + if (rc) { + DP_ERR("failed to create pps cmd %d\n", rc); + return; + } + dsc->pps_len = DSC_1_1_PPS_PARAMETER_SET_ELEMENTS; dp_panel_dsc_prepare_pps_packet(dp_panel); dsc->slice_per_pkt = comp_info->dsc_info.slice_per_pkt - 1; @@ -3245,6 +2918,7 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, struct msm_compression_info *comp_info; bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ? true : false; + int rc; dp_mode->timing.h_active = drm_mode->hdisplay; dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; @@ -3292,8 +2966,19 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, return; } - dp_panel_dsc_populate_static_params(&comp_info->dsc_info, - dp_panel); + rc = sde_dsc_populate_dsc_config(&comp_info->dsc_info.config, 0); + if (rc) { + DP_DEBUG("failed populating dsc params \n"); + return; + } + + rc = sde_dsc_populate_dsc_private_params(&comp_info->dsc_info, + dp_mode->timing.h_active); + if (rc) { + DP_DEBUG("failed populating other dsc params\n"); + return; + } + dp_panel_dsc_pclk_param_calc(dp_panel, &comp_info->dsc_info, comp_info->comp_ratio, diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index a7986d7a22..cc6cac32eb 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -13,6 +13,7 @@ #include "dsi_panel.h" #include "dsi_catalog.h" #include "sde_dbg.h" +#include "sde_dsc_helper.h" #define MMSS_MISC_CLAMP_REG_OFF 0x0014 #define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21)) @@ -369,9 +370,9 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, memcpy(&dsc, mode->dsc, sizeof(dsc)); pic_width = roi ? roi->w : mode->h_active; - this_frame_slices = pic_width / dsc.slice_width; - intf_ip_w = this_frame_slices * dsc.slice_width; - dsi_dsc_pclk_param_calc(&dsc, intf_ip_w); + this_frame_slices = pic_width / dsc.config.slice_width; + intf_ip_w = this_frame_slices * dsc.config.slice_width; + sde_dsc_populate_dsc_private_params(&dsc, intf_ip_w); if (vc_id != 0) offset = 16; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e9162e2354..5286d17910 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -1669,6 +1669,9 @@ static void adjust_timing_by_ctrl_count(const struct dsi_display *display, mode->timing.h_back_porch /= display->ctrl_count; mode->timing.h_skew /= display->ctrl_count; mode->pixel_clk_khz /= display->ctrl_count; + if (mode->priv_info->dsc_enabled) + mode->priv_info->dsc.config.pic_width *= + display->ctrl_count; } } @@ -7236,7 +7239,6 @@ int dsi_display_enable(struct dsi_display *display) /* Block sending pps command if modeset is due to fps difference */ if ((mode->priv_info->dsc_enabled) && !(mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)) { - mode->priv_info->dsc.pic_width *= display->ctrl_count; rc = dsi_panel_update_pps(display->panel); if (rc) { DSI_ERR("[%s] panel pps cmd update failed, rc=%d\n", diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 969e9d9473..85a7e62b72 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -13,6 +13,7 @@ #include "dsi_panel.h" #include "dsi_ctrl_hw.h" #include "dsi_parser.h" +#include "sde_dsc_helper.h" /** * topology is currently defined by a set of following 3 values: @@ -32,75 +33,13 @@ #define DEFAULT_PANEL_PREFILL_LINES 25 #define MIN_PREFILL_LINES 35 -enum dsi_dsc_ratio_type { - DSC_8BPC_8BPP, - DSC_10BPC_8BPP, - DSC_12BPC_8BPP, - DSC_10BPC_10BPP, - DSC_RATIO_TYPE_MAX -}; - -static u32 dsi_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, - 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; - -/* - * DSC 1.1 - * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type - */ -static char dsi_dsc_rc_range_min_qp_1_1[][15] = { - {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12}, - {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, - {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21}, - {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, - }; - -/* - * DSC 1.1 SCR - * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type - */ -static char dsi_dsc_rc_range_min_qp_1_1_scr1[][15] = { - {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, - {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, - {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, - {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, - }; - -/* - * DSC 1.1 - * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type - */ -static char dsi_dsc_rc_range_max_qp_1_1[][15] = { - {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, - {4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, - {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23}, - {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, - }; - -/* - * DSC 1.1 SCR - * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type - */ -static char dsi_dsc_rc_range_max_qp_1_1_scr1[][15] = { - {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, - {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, - {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 23}, - {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, - }; - -/* - * DSC 1.1 and DSC 1.1 SCR - * Rate control - bpg offset values - */ -static char dsi_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, - -8, -10, -10, -12, -12, -12, -12}; int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf, - int pps_id) + int pps_id, u32 size) { char *bp; - char data; - int i, bpp; char *dbgbp; + u32 header_size = 7; dbgbp = buf; bp = buf; @@ -113,99 +52,7 @@ int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf, *bp++ = 0; *bp++ = 128; - *bp++ = (dsc->version & 0xff); /* pps0 */ - *bp++ = (pps_id & 0xff); /* pps1 */ - bp++; /* pps2, reserved */ - - data = dsc->line_buf_depth & 0x0f; - data |= ((dsc->bpc & 0xf) << 4); - *bp++ = data; /* pps3 */ - - bpp = dsc->bpp; - bpp <<= 4; /* 4 fraction bits */ - data = (bpp >> 8); - data &= 0x03; /* upper two bits */ - data |= ((dsc->block_pred_enable & 0x1) << 5); - data |= ((dsc->convert_rgb & 0x1) << 4); - data |= ((dsc->enable_422 & 0x1) << 3); - data |= ((dsc->vbr_enable & 0x1) << 2); - *bp++ = data; /* pps4 */ - *bp++ = (bpp & 0xff); /* pps5 */ - - *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ - *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ - *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ - *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ - - *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ - *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ - *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ - *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ - - *bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */ - *bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */ - - *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16, bit 0, 1 */ - *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ - - *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ - *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ - - bp++; /* pps20, reserved */ - - *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ - - *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ - *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ - - *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ - *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ - - bp++; /* pps26, reserved */ - - *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ - - *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ - *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ - *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ - *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ - - *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ - *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ - - *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ - *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ - - *bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */ - *bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */ - - *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ - *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ - - *bp++ = (dsc->edge_factor & 0x0f); /* pps40 */ - - *bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */ - *bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */ - - data = ((dsc->tgt_offset_hi & 0xf) << 4); - data |= (dsc->tgt_offset_lo & 0x0f); - *bp++ = data; /* pps43 */ - - for (i = 0; i < 14; i++) - *bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */ - - for (i = 0; i < 15; i++) { /* pps58 - pps87 */ - data = (dsc->range_min_qp[i] & 0x1f); - data <<= 3; - data |= ((dsc->range_max_qp[i] >> 2) & 0x07); - *bp++ = data; - data = (dsc->range_max_qp[i] & 0x03); - data <<= 6; - data |= (dsc->range_bpg_offset[i] & 0x3f); - *bp++ = data; - } - - return 128; + return sde_dsc_create_pps_buf_cmd(dsc, bp, pps_id, size - header_size); } static int dsi_panel_vreg_get(struct dsi_panel *panel) @@ -2300,198 +2147,6 @@ error: return rc; } -void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width) -{ - int slice_per_pkt, slice_per_intf; - int bytes_in_slice, total_bytes_per_intf; - - if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || - (intf_width < dsc->slice_width)) { - DSI_ERR("invalid input, intf_width=%d slice_width=%d\n", - intf_width, dsc ? dsc->slice_width : -1); - return; - } - - slice_per_pkt = dsc->slice_per_pkt; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); - - /* - * If slice_per_pkt is greater than slice_per_intf then default to 1. - * This can happen during partial update. - */ - if (slice_per_pkt > slice_per_intf) - slice_per_pkt = 1; - - bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); - total_bytes_per_intf = bytes_in_slice * slice_per_intf; - - dsc->eol_byte_num = total_bytes_per_intf % 3; - dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); - dsc->bytes_in_slice = bytes_in_slice; - dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; - dsc->pkt_per_line = slice_per_intf / slice_per_pkt; -} - - -int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc) -{ - int bpp, bpc; - int mux_words_size; - int groups_per_line, groups_total; - int min_rate_buffer_size; - int hrd_delay; - int pre_num_extra_mux_bits, num_extra_mux_bits; - int slice_bits; - int data; - int final_value, final_scale; - int ratio_index, mod_offset; - - dsc->rc_model_size = 8192; - - if (dsc->version == 0x11 && dsc->scr_rev == 0x1) - dsc->first_line_bpg_offset = 15; - else - dsc->first_line_bpg_offset = 12; - - dsc->edge_factor = 6; - dsc->tgt_offset_hi = 3; - dsc->tgt_offset_lo = 3; - dsc->enable_422 = 0; - dsc->convert_rgb = 1; - dsc->vbr_enable = 0; - - dsc->buf_thresh = dsi_dsc_rc_buf_thresh; - - bpp = dsc->bpp; - bpc = dsc->bpc; - - if ((bpc == 12) && (bpp == 8)) - ratio_index = DSC_12BPC_8BPP; - else if ((bpc == 10) && (bpp == 8)) - ratio_index = DSC_10BPC_8BPP; - else if ((bpc == 10) && (bpp == 10)) - ratio_index = DSC_10BPC_10BPP; - else - ratio_index = DSC_8BPC_8BPP; - - if (dsc->version == 0x11 && dsc->scr_rev == 0x1) { - dsc->range_min_qp = - dsi_dsc_rc_range_min_qp_1_1_scr1[ratio_index]; - dsc->range_max_qp = - dsi_dsc_rc_range_max_qp_1_1_scr1[ratio_index]; - } else { - dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1[ratio_index]; - dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1[ratio_index]; - } - dsc->range_bpg_offset = dsi_dsc_rc_range_bpg_offset; - - if (bpp == 8) { - dsc->initial_offset = 6144; - dsc->initial_xmit_delay = 512; - } else if (bpp == 10) { - dsc->initial_offset = 5632; - dsc->initial_xmit_delay = 410; - } else { - dsc->initial_offset = 2048; - dsc->initial_xmit_delay = 341; - } - - dsc->line_buf_depth = bpc + 1; - - if (bpc == 8) { - dsc->input_10_bits = 0; - dsc->min_qp_flatness = 3; - dsc->max_qp_flatness = 12; - dsc->quant_incr_limit0 = 11; - dsc->quant_incr_limit1 = 11; - mux_words_size = 48; - } else if (bpc == 10) { /* 10bpc */ - dsc->input_10_bits = 1; - dsc->min_qp_flatness = 7; - dsc->max_qp_flatness = 16; - dsc->quant_incr_limit0 = 15; - dsc->quant_incr_limit1 = 15; - mux_words_size = 48; - } else { /* 12 bpc */ - dsc->input_10_bits = 0; - dsc->min_qp_flatness = 11; - dsc->max_qp_flatness = 20; - dsc->quant_incr_limit0 = 19; - dsc->quant_incr_limit1 = 19; - mux_words_size = 64; - } - - mod_offset = dsc->slice_width % 3; - switch (mod_offset) { - case 0: - dsc->slice_last_group_size = 2; - break; - case 1: - dsc->slice_last_group_size = 0; - break; - case 2: - dsc->slice_last_group_size = 1; - break; - default: - break; - } - - dsc->det_thresh_flatness = 2 << (bpc - 8); - - groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); - - dsc->chunk_size = dsc->slice_width * bpp / 8; - if ((dsc->slice_width * bpp) % 8) - dsc->chunk_size++; - - /* rbs-min */ - min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + - dsc->initial_xmit_delay * bpp + - groups_per_line * dsc->first_line_bpg_offset; - - hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); - - dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; - - dsc->initial_scale_value = 8 * dsc->rc_model_size / - (dsc->rc_model_size - dsc->initial_offset); - - slice_bits = 8 * dsc->chunk_size * dsc->slice_height; - - groups_total = groups_per_line * dsc->slice_height; - - data = dsc->first_line_bpg_offset * 2048; - - dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); - - pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2); - - num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - - ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); - - data = 2048 * (dsc->rc_model_size - dsc->initial_offset - + num_extra_mux_bits); - dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); - - data = dsc->initial_xmit_delay * bpp; - final_value = dsc->rc_model_size - data + num_extra_mux_bits; - - final_scale = 8 * dsc->rc_model_size / - (dsc->rc_model_size - final_value); - - dsc->final_offset = final_value; - - data = (final_scale - 9) * (dsc->nfl_bpg_offset + - dsc->slice_bpg_offset); - dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; - - dsc->scale_decrement_interval = groups_per_line / - (dsc->initial_scale_value - 8); - - return 0; -} - - static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, struct dsi_parser_utils *utils) { @@ -2565,14 +2220,25 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, rc = utils->read_u32(utils->data, "qcom,mdss-dsc-version", &data); if (rc) { - priv_info->dsc.version = 0x11; + priv_info->dsc.config.dsc_version_major = 0x1; + priv_info->dsc.config.dsc_version_minor = 0x1; rc = 0; } else { - priv_info->dsc.version = data & 0xff; - /* only support DSC 1.1 rev */ - if (priv_info->dsc.version != 0x11) { - DSI_ERR("%s: DSC version:%d not supported\n", __func__, - priv_info->dsc.version); + /* BITS[0..3] provides minor version and BITS[4..7] provide + * major version information + */ + priv_info->dsc.config.dsc_version_major = (data >> 4) & 0x0F; + priv_info->dsc.config.dsc_version_minor = data & 0x0F; + if ((priv_info->dsc.config.dsc_version_major != 0x1) && + ((priv_info->dsc.config.dsc_version_minor + != 0x1) || + (priv_info->dsc.config.dsc_version_minor + != 0x2))) { + DSI_ERR("%s:unsupported major:%d minor:%d version\n", + __func__, + priv_info->dsc.config.dsc_version_major, + priv_info->dsc.config.dsc_version_minor + ); rc = -EINVAL; goto error; } @@ -2598,25 +2264,25 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, DSI_ERR("failed to parse qcom,mdss-dsc-slice-height\n"); goto error; } - priv_info->dsc.slice_height = data; + priv_info->dsc.config.slice_height = data; rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-width", &data); if (rc) { DSI_ERR("failed to parse qcom,mdss-dsc-slice-width\n"); goto error; } - priv_info->dsc.slice_width = data; + priv_info->dsc.config.slice_width = data; intf_width = mode->timing.h_active; - if (intf_width % priv_info->dsc.slice_width) { + if (intf_width % priv_info->dsc.config.slice_width) { DSI_ERR("invalid slice width for the intf width:%d slice width:%d\n", - intf_width, priv_info->dsc.slice_width); + intf_width, priv_info->dsc.config.slice_width); rc = -EINVAL; goto error; } - priv_info->dsc.pic_width = mode->timing.h_active; - priv_info->dsc.pic_height = mode->timing.v_active; + priv_info->dsc.config.pic_width = mode->timing.h_active; + priv_info->dsc.config.pic_height = mode->timing.v_active; rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-per-pkt", &data); if (rc) { @@ -2634,7 +2300,7 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, DSI_ERR("failed to parse qcom,mdss-dsc-bit-per-component\n"); goto error; } - priv_info->dsc.bpc = data; + priv_info->dsc.config.bits_per_component = data; rc = utils->read_u32(utils->data, "qcom,mdss-pps-delay-ms", &data); if (rc) { @@ -2649,16 +2315,28 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, DSI_ERR("failed to parse qcom,mdss-dsc-bit-per-pixel\n"); goto error; } - priv_info->dsc.bpp = data; + priv_info->dsc.config.bits_per_pixel = data << 4; - priv_info->dsc.block_pred_enable = utils->read_bool(utils->data, + priv_info->dsc.config.block_pred_enable = utils->read_bool(utils->data, "qcom,mdss-dsc-block-prediction-enable"); - priv_info->dsc.full_frame_slices = DIV_ROUND_UP(intf_width, - priv_info->dsc.slice_width); + priv_info->dsc.config.slice_count = DIV_ROUND_UP(intf_width, + priv_info->dsc.config.slice_width); - dsi_dsc_populate_static_param(&priv_info->dsc); - dsi_dsc_pclk_param_calc(&priv_info->dsc, intf_width); + rc = sde_dsc_populate_dsc_config(&priv_info->dsc.config, + priv_info->dsc.scr_rev); + if (rc) { + DSI_DEBUG("failed populating dsc params \n"); + rc = -EINVAL; + goto error; + } + + rc = sde_dsc_populate_dsc_private_params(&priv_info->dsc, intf_width); + if (rc) { + DSI_DEBUG("failed populating other dsc params \n"); + rc = -EINVAL; + goto error; + } mode->timing.dsc_enabled = true; mode->timing.dsc = &priv_info->dsc; @@ -3588,6 +3266,7 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, struct dsi_display_mode *display_mode; u32 jitter_numer, jitter_denom, prefill_lines; u32 min_threshold_us, prefill_time_us; + u16 bpp; /* Packet overlead in bits,2 bytes header + 2 bytes checksum * + 1 byte dcs data command. @@ -3602,11 +3281,12 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); if (timing->dsc_enabled) { - nslices = (timing->h_active)/(dsc->slice_width); + nslices = (timing->h_active)/(dsc->config.slice_width); /* (slice width x bit-per-pixel + packet overhead) x * number of slices x height x fps / lane */ - bits_per_line = ((dsc->slice_width * dsc->bpp) + + bpp = DSC_BPP(dsc->config); + bits_per_line = ((dsc->config.slice_width * bpp) + packet_overhead) * nslices; bits_per_line = bits_per_line / (config->num_data_lanes); @@ -3880,7 +3560,12 @@ int dsi_panel_update_pps(struct dsi_panel *panel) set = &priv_info->cmd_sets[DSI_CMD_SET_PPS]; - dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0); + rc = dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0, + DSI_CMD_PPS_SIZE); + if (rc) { + DSI_ERR("failed to create pps cmd, rc=%d\n", rc); + goto error; + } rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd, DSI_CMD_PPS_SIZE, 1, set->cmds); if (rc) { diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 3ecff84831..06af73d5b5 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -45,6 +45,7 @@ #include #include #include +#include #include "sde_power_handle.h" @@ -311,114 +312,44 @@ struct msm_roi_caps { /** * struct msm_display_dsc_info - defines dsc configuration - * @version: DSC version. + * @config DSC encoder configuration * @scr_rev: DSC revision. - * @pic_height: Picture height in pixels. - * @pic_width: Picture width in pixels. * @initial_lines: Number of initial lines stored in encoder. * @pkt_per_line: Number of packets per line. * @bytes_in_slice: Number of bytes in slice. * @eol_byte_num: Valid bytes at the end of line. + * @bytes_per_pkt Number of bytes in DSI packet * @pclk_per_line: Compressed width. - * @full_frame_slices: Number of slice per interface. - * @slice_height: Slice height in pixels. - * @slice_width: Slice width in pixels. - * @chunk_size: Chunk size in bytes for slice multiplexing. * @slice_last_group_size: Size of last group in pixels. - * @bpp: Target bits per pixel. - * @bpc: Number of bits per component. - * @line_buf_depth: Line buffer bit depth. - * @block_pred_enable: Block prediction enabled/disabled. - * @vbr_enable: VBR mode. - * @enable_422: Indicates if input uses 4:2:2 sampling. - * @convert_rgb: DSC color space conversion. - * @input_10_bits: 10 bit per component input. * @slice_per_pkt: Number of slices per packet. - * @initial_dec_delay: Initial decoding delay. - * @initial_xmit_delay: Initial transmission delay. - * @initial_scale_value: Scale factor value at the beginning of a slice. - * @scale_decrement_interval: Scale set up at the beginning of a slice. - * @scale_increment_interval: Scale set up at the end of a slice. - * @first_line_bpg_offset: Extra bits allocated on the first line of a slice. - * @nfl_bpg_offset: Slice specific settings. - * @slice_bpg_offset: Slice specific settings. - * @initial_offset: Initial offset at the start of a slice. - * @final_offset: Maximum end-of-slice value. - * @rc_model_size: Number of bits in RC model. * @det_thresh_flatness: Flatness threshold. - * @max_qp_flatness: Maximum QP for flatness adjustment. - * @min_qp_flatness: Minimum QP for flatness adjustment. - * @edge_factor: Ratio to detect presence of edge. - * @quant_incr_limit0: QP threshold. - * @quant_incr_limit1: QP threshold. - * @tgt_offset_hi: Upper end of variability range. - * @tgt_offset_lo: Lower end of variability range. - * @buf_thresh: Thresholds in RC model - * @range_min_qp: Min QP allowed. - * @range_max_qp: Max QP allowed. - * @range_bpg_offset: Bits per group adjustment. * @extra_width: Extra width required in timing calculations. * @pps_delay_ms: Post PPS command delay in milliseconds. */ struct msm_display_dsc_info { - u8 version; + struct drm_dsc_config config; u8 scr_rev; - int pic_height; - int pic_width; - int slice_height; - int slice_width; - int initial_lines; int pkt_per_line; int bytes_in_slice; int bytes_per_pkt; int eol_byte_num; int pclk_per_line; - int full_frame_slices; int slice_last_group_size; - int bpp; - int bpc; - int line_buf_depth; - int slice_per_pkt; - int chunk_size; - bool block_pred_enable; - int vbr_enable; - int enable_422; - int convert_rgb; - int input_10_bits; - - int initial_dec_delay; - int initial_xmit_delay; - int initial_scale_value; - int scale_decrement_interval; - int scale_increment_interval; - int first_line_bpg_offset; - int nfl_bpg_offset; - int slice_bpg_offset; - int initial_offset; - int final_offset; - - int rc_model_size; int det_thresh_flatness; - int max_qp_flatness; - int min_qp_flatness; - int edge_factor; - int quant_incr_limit0; - int quant_incr_limit1; - int tgt_offset_hi; - int tgt_offset_lo; - - u32 *buf_thresh; - char *range_min_qp; - char *range_max_qp; - char *range_bpg_offset; - u32 extra_width; u32 pps_delay_ms; }; + +/** + * Bits/pixel target >> 4 (removing the fractional bits) + * returns the integer bpp value from the drm_dsc_config struct + */ +#define DSC_BPP(config) ((config).bits_per_pixel >> 4) + /** * struct msm_compression_info - defined panel compression * @comp_type: type of compression supported diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 1cdc033283..1e1559dcf2 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3492,6 +3492,7 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) struct msm_display_dsc_info *dsc = NULL; struct sde_encoder_virt *sde_enc; struct sde_hw_pingpong *hw_pp; + u16 bpp; if (!phys || !phys->connector || !phys->hw_pp || !phys->hw_pp->ops.setup_dither || !phys->parent) @@ -3506,7 +3507,8 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) sde_enc = to_sde_encoder_virt(drm_enc); dsc = &sde_enc->mode_info.comp_info.dsc_info; /* disable dither for 10 bpp or 10bpc dsc config */ - if (dsc->bpp == 10 || dsc->bpc == 10) { + bpp = DSC_BPP(dsc->config); + if (bpp == 10 || dsc->config.bits_per_component == 10) { phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0); return; } diff --git a/msm/sde/sde_encoder_dce.c b/msm/sde/sde_encoder_dce.c index 0886e6eb3a..7ce71e34be 100644 --- a/msm/sde/sde_encoder_dce.c +++ b/msm/sde/sde_encoder_dce.c @@ -23,6 +23,7 @@ #include "sde_crtc.h" #include "sde_trace.h" #include "sde_core_irq.h" +#include "sde_dsc_helper.h" #define SDE_DEBUG_DCE(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\ (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) @@ -55,7 +56,6 @@ bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc) } static int _dce_dsc_update_pic_dim(struct msm_display_dsc_info *dsc, - int pic_width, int pic_height) { if (!dsc || !pic_width || !pic_height) { @@ -64,53 +64,20 @@ static int _dce_dsc_update_pic_dim(struct msm_display_dsc_info *dsc, return -EINVAL; } - if ((pic_width % dsc->slice_width) || - (pic_height % dsc->slice_height)) { + if ((pic_width % dsc->config.slice_width) || + (pic_height % dsc->config.slice_height)) { SDE_ERROR("pic_dim=%dx%d has to be multiple of slice=%dx%d\n", pic_width, pic_height, - dsc->slice_width, dsc->slice_height); + dsc->config.slice_width, dsc->config.slice_height); return -EINVAL; } - dsc->pic_width = pic_width; - dsc->pic_height = pic_height; + dsc->config.pic_width = pic_width; + dsc->config.pic_height = pic_height; return 0; } -static void _dce_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, - int intf_width) -{ - int slice_per_pkt, slice_per_intf; - int bytes_in_slice, total_bytes_per_intf; - - if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || - (intf_width < dsc->slice_width)) { - SDE_ERROR("invalid input: intf_width=%d slice_width=%d\n", - intf_width, dsc ? dsc->slice_width : -1); - return; - } - - slice_per_pkt = dsc->slice_per_pkt; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); - - /* - * If slice_per_pkt is greater than slice_per_intf then default to 1. - * This can happen during partial update. - */ - if (slice_per_pkt > slice_per_intf) - slice_per_pkt = 1; - - bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); - total_bytes_per_intf = bytes_in_slice * slice_per_intf; - - dsc->eol_byte_num = total_bytes_per_intf % 3; - dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); - dsc->bytes_in_slice = bytes_in_slice; - dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; - dsc->pkt_per_line = slice_per_intf / slice_per_pkt; -} - static int _dce_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, int enc_ip_width, int dsc_cmn_mode) @@ -124,20 +91,23 @@ static int _dce_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, int output_rate_ratio_complement, container_slice_width; int rtl_num_components, multi_hs_c, multi_hs_d; + int bpc = dsc->config.bits_per_component; + int bpp = DSC_BPP(dsc->config); + int num_of_active_ss = dsc->config.slice_count; + bool native_422 = dsc->config.native_422; + bool native_420 = dsc->config.native_420; + /* Hardent core config */ int multiplex_mode_enable = 0, split_panel_enable = 0; int rtl_max_bpc = 10, rtl_output_data_width = 64; int pipeline_latency = 28; - int bpc = dsc->bpc, bpp = dsc->bpp; - int num_of_active_ss = dsc->full_frame_slices; - bool native_422 = false, native_420 = false; if (dsc_cmn_mode & DSC_MODE_MULTIPLEX) multiplex_mode_enable = 1; if (dsc_cmn_mode & DSC_MODE_SPLIT_PANEL) split_panel_enable = 0; container_slice_width = (native_422 ? - dsc->slice_width / 2 : dsc->slice_width); + dsc->config.slice_width / 2 : dsc->config.slice_width); max_muxword_size = ((rtl_max_bpc >= 12) ? 64 : 48); max_se_size = 4 * (rtl_max_bpc + 1); max_ssm_delay = max_se_size + max_muxword_size - 1; @@ -156,9 +126,9 @@ static int _dce_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, ob_data_width_4comps : ob_data_width_3comps); obuf_latency = DIV_ROUND_UP((9 * ob_data_width + mux_word_size), compress_bpp_group) + 1; - base_hs_latency = dsc->initial_xmit_delay + input_ssm_out_latency - + obuf_latency; - chunk_bits = 8 * dsc->chunk_size; + base_hs_latency = dsc->config.initial_xmit_delay + + input_ssm_out_latency + obuf_latency; + chunk_bits = 8 * dsc->config.slice_chunk_size; output_rate_ratio_complement = ob_data_width - compress_bpp_group; output_rate_extra_budget_bits = (output_rate_ratio_complement * chunk_bits) >> @@ -196,8 +166,8 @@ static bool _dce_dsc_ich_reset_override_needed(bool pu_en, * then HW will generate ich_reset at end of the slice. This is a * mismatch. Prevent this by overriding HW's decision. */ - return pu_en && dsc && (dsc->full_frame_slices > 1) && - (dsc->slice_width == dsc->pic_width); + return pu_en && dsc && (dsc->config.slice_count > 1) && + (dsc->config.slice_width == dsc->config.pic_width); } static void _dce_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc, @@ -330,13 +300,13 @@ static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, if (enc_master->intf_mode == INTF_MODE_VIDEO) dsc_common_mode |= DSC_MODE_VIDEO; - this_frame_slices = roi->w / dsc->slice_width; - intf_ip_w = this_frame_slices * dsc->slice_width; + this_frame_slices = roi->w / dsc->config.slice_width; + intf_ip_w = this_frame_slices * dsc->config.slice_width; if ((!half_panel_partial_update) && (num_intf > 1)) intf_ip_w /= 2; - _dce_dsc_pclk_param_calc(dsc, intf_ip_w); + sde_dsc_populate_dsc_private_params(dsc, intf_ip_w); /* * in dsc merge case: when using 2 encoders for the same stream, diff --git a/msm/sde/sde_hw_dsc.c b/msm/sde/sde_hw_dsc.c index 1e07b470c1..3ac185c182 100644 --- a/msm/sde/sde_hw_dsc.c +++ b/msm/sde/sde_hw_dsc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "sde_hw_mdss.h" @@ -58,101 +58,101 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc, data |= (initial_lines << 20); data |= (dsc->slice_last_group_size << 18); - data |= (dsc->bpp << 12); - data |= (dsc->block_pred_enable << 7); - data |= (dsc->line_buf_depth << 3); - data |= (dsc->enable_422 << 2); - data |= (dsc->convert_rgb << 1); - data |= dsc->input_10_bits; + /* integer bpp support only */ + data |= (dsc->config.bits_per_pixel << 8); + data |= (dsc->config.block_pred_enable << 7); + data |= (dsc->config.line_buf_depth << 3); + data |= (dsc->config.simple_422 << 2); + data |= (dsc->config.convert_rgb << 1); + if (dsc->config.bits_per_component == 10) + data |= BIT(0); SDE_REG_WRITE(dsc_c, DSC_ENC, data); - data = dsc->pic_width << 16; - data |= dsc->pic_height; + data = dsc->config.pic_width << 16; + data |= dsc->config.pic_height; SDE_REG_WRITE(dsc_c, DSC_PICTURE, data); - data = dsc->slice_width << 16; - data |= dsc->slice_height; + data = dsc->config.slice_width << 16; + data |= dsc->config.slice_height; SDE_REG_WRITE(dsc_c, DSC_SLICE, data); - data = dsc->chunk_size << 16; + data = dsc->config.slice_chunk_size << 16; SDE_REG_WRITE(dsc_c, DSC_CHUNK_SIZE, data); - data = dsc->initial_dec_delay << 16; - data |= dsc->initial_xmit_delay; + data = dsc->config.initial_dec_delay << 16; + data |= dsc->config.initial_xmit_delay; SDE_REG_WRITE(dsc_c, DSC_DELAY, data); - data = dsc->initial_scale_value; + data = dsc->config.initial_scale_value; SDE_REG_WRITE(dsc_c, DSC_SCALE_INITIAL, data); - data = dsc->scale_decrement_interval; + data = dsc->config.scale_decrement_interval; SDE_REG_WRITE(dsc_c, DSC_SCALE_DEC_INTERVAL, data); - data = dsc->scale_increment_interval; + data = dsc->config.scale_increment_interval; SDE_REG_WRITE(dsc_c, DSC_SCALE_INC_INTERVAL, data); - data = dsc->first_line_bpg_offset; + data = dsc->config.first_line_bpg_offset; SDE_REG_WRITE(dsc_c, DSC_FIRST_LINE_BPG_OFFSET, data); - data = dsc->nfl_bpg_offset << 16; - data |= dsc->slice_bpg_offset; + data = dsc->config.nfl_bpg_offset << 16; + data |= dsc->config.slice_bpg_offset; SDE_REG_WRITE(dsc_c, DSC_BPG_OFFSET, data); - data = dsc->initial_offset << 16; - data |= dsc->final_offset; + data = dsc->config.initial_offset << 16; + data |= dsc->config.final_offset; SDE_REG_WRITE(dsc_c, DSC_DSC_OFFSET, data); data = dsc->det_thresh_flatness << 10; - data |= dsc->max_qp_flatness << 5; - data |= dsc->min_qp_flatness; + data |= dsc->config.flatness_max_qp << 5; + data |= dsc->config.flatness_min_qp; SDE_REG_WRITE(dsc_c, DSC_FLATNESS, data); - data = dsc->rc_model_size; + data = dsc->config.rc_model_size; SDE_REG_WRITE(dsc_c, DSC_RC_MODEL_SIZE, data); - data = dsc->tgt_offset_lo << 18; - data |= dsc->tgt_offset_hi << 14; - data |= dsc->quant_incr_limit1 << 9; - data |= dsc->quant_incr_limit0 << 4; - data |= dsc->edge_factor; + data = dsc->config.rc_tgt_offset_low << 18; + data |= dsc->config.rc_tgt_offset_high << 14; + data |= dsc->config.rc_quant_incr_limit1 << 9; + data |= dsc->config.rc_quant_incr_limit0 << 4; + data |= dsc->config.rc_edge_factor; SDE_REG_WRITE(dsc_c, DSC_RC, data); } static void sde_hw_dsc_config_thresh(struct sde_hw_dsc *hw_dsc, struct msm_display_dsc_info *dsc) { - u32 *lp; - char *cp; + u16 *lp; int i; struct sde_hw_blk_reg_map *dsc_c = &hw_dsc->hw; u32 off = 0x0; + struct drm_dsc_rc_range_parameters *rc = + dsc->config.rc_range_params; - lp = dsc->buf_thresh; + lp = dsc->config.rc_buf_thresh; off = DSC_RC_BUF_THRESH; - for (i = 0; i < 14; i++) { + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) { SDE_REG_WRITE(dsc_c, off, *lp++); off += 4; } - cp = dsc->range_min_qp; off = DSC_RANGE_MIN_QP; - for (i = 0; i < 15; i++) { - SDE_REG_WRITE(dsc_c, off, *cp++); + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + SDE_REG_WRITE(dsc_c, off, rc[i].range_min_qp); off += 4; } - cp = dsc->range_max_qp; off = DSC_RANGE_MAX_QP; - for (i = 0; i < 15; i++) { - SDE_REG_WRITE(dsc_c, off, *cp++); + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + SDE_REG_WRITE(dsc_c, off, rc[i].range_max_qp); off += 4; } - cp = dsc->range_bpg_offset; off = DSC_RANGE_BPG_OFFSET; - for (i = 0; i < 15; i++) { - SDE_REG_WRITE(dsc_c, off, *cp++); + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + SDE_REG_WRITE(dsc_c, off, rc[i].range_bpg_offset); off += 4; } } diff --git a/msm/sde_dsc_helper.c b/msm/sde_dsc_helper.c new file mode 100644 index 0000000000..66654f913e --- /dev/null +++ b/msm/sde_dsc_helper.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + */ + +#include "msm_drv.h" +#include "sde_dsc_helper.h" +#include "sde_kms.h" + + +#define SDE_DSC_PPS_SIZE 128 + +enum sde_dsc_ratio_type { + DSC_V11_8BPC_8BPP, + DSC_V11_10BPC_8BPP, + DSC_V11_10BPC_10BPP, + DSC_V11_SCR1_8BPC_8BPP, + DSC_V11_SCR1_10BPC_8BPP, + DSC_V11_SCR1_10BPC_10BPP, + DSC_V12_444_8BPC_8BPP = DSC_V11_SCR1_8BPC_8BPP, + DSC_V12_444_10BPC_8BPP = DSC_V11_SCR1_10BPC_8BPP, + DSC_V12_444_10BPC_10BPP = DSC_V11_SCR1_10BPC_10BPP, + DSC_V12_422_8BPC_7BPP, + DSC_V12_422_8BPC_8BPP, + DSC_V12_422_10BPC_7BPP, + DSC_V12_422_10BPC_10BPP, + DSC_V12_420_8BPC_6BPP, + DSC_V12_420_10BPC_6BPP, + DSC_V12_420_10BPC_7_5BPP, + DSC_RATIO_TYPE_MAX +}; + +static u16 sde_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = + {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, + 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; + +/* + * Rate control - Min QP values for each ratio type in sde_dsc_ratio_type + */ +static char sde_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { + /* DSC v1.1 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + /* DSC v1.1 SCR and DSC v1.2 RGB 444 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + /* DSC v1.2 YUV422 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, + {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, + {0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12}, + /* DSC v1.2 YUV420 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, + {0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14}, + {0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12}, +}; + +/* + * Rate control - Max QP values for each ratio type in sde_dsc_ratio_type + */ +static char sde_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { + /* DSC v1.1 */ + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, + {4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + /* DSC v1.1 SCR and DSC v1.2 RGB 444 */ + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, + {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + /* DSC v1.2 YUV422 */ + {3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12}, + {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + {2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13}, + /* DSC v1.2 YUV420 */ + {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12}, + {2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15}, + {2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13}, + }; + + +/* + * Rate control - bpg offset values + */ +static char sde_dsc_rc_range_bpg_offset[DSC_NUM_BUF_RANGES] = + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}; + + +static int _get_rc_table_index(struct drm_dsc_config *dsc, int scr_ver) +{ + int bpp, bpc; + + if (dsc->dsc_version_major != 0x1) { + SDE_ERROR("unsupported major version %d\n", + dsc->dsc_version_major); + return -EINVAL; + } + + bpp = DSC_BPP(*dsc); + bpc = dsc->bits_per_component; + + if ((dsc->dsc_version_minor == 0x1) && (scr_ver == 0x0)) { + if ((bpc == 8) && (bpp == 8)) + return DSC_V11_8BPC_8BPP; + if ((bpc == 10) && (bpp == 8)) + return DSC_V11_10BPC_10BPP; + else if ((bpc == 10) && (bpp == 10)) + return DSC_V11_10BPC_10BPP; + else + SDE_ERROR("unsupported bpc:%d, bpp:%d\n", bpc, bpp); + } else if (((dsc->dsc_version_minor == 0x1) && (scr_ver == 0x1)) || + ((dsc->dsc_version_minor = 0x2) && + !dsc->native_422 & !dsc->native_420)) { + if ((bpc == 8) && (bpp == 8)) + return DSC_V11_SCR1_8BPC_8BPP; + if ((bpc == 10) && (bpp == 8)) + return DSC_V11_SCR1_10BPC_8BPP; + else if ((bpc == 10) && (bpp == 10)) + return DSC_V11_SCR1_10BPC_10BPP; + else + SDE_ERROR("unsupported bpc:%d, bpp:%d\n", bpc, bpp); + } else if ((dsc->dsc_version_minor = 0x2) && dsc->native_422) { + if ((bpc == 8) && (bpp == 7)) + return DSC_V12_422_8BPC_7BPP; + else if ((bpc == 8) && (bpp == 8)) + return DSC_V12_422_8BPC_8BPP; + else if ((bpc == 10) && (bpp == 7)) + return DSC_V12_422_10BPC_7BPP; + else if ((bpc == 10) && (bpp == 10)) + return DSC_V12_422_10BPC_10BPP; + else + SDE_ERROR("unsupported bpc:%d, bpp:%d\n", bpc, bpp); + } else if ((dsc->dsc_version_minor = 0x2) && dsc->native_420) { + if ((bpc == 8) && (bpp == 6)) + return DSC_V12_420_8BPC_6BPP; + else if ((bpc == 10) && (bpp == 6)) + return DSC_V12_420_10BPC_6BPP; + else + SDE_ERROR("unsupported bpc:%d, bpp:%d\n", bpc, bpp); + } + + SDE_ERROR("unsupported DSC version %d, %d %d\n", + dsc->dsc_version_major, + dsc->dsc_version_minor, + scr_ver); + return -EINVAL; + +} + +int sde_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver) { + int bpp, bpc; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int data; + int final_value, final_scale; + int i, ratio_idx; + + dsc->rc_model_size = 8192; + + if (dsc->dsc_version_major == 0x1 && ((dsc->dsc_version_minor == 0x1 && + scr_ver == 0x1) || + (dsc->dsc_version_minor == 0x2))) + dsc->first_line_bpg_offset = 15; + else + dsc->first_line_bpg_offset = 12; + + dsc->rc_edge_factor = 6; + dsc->rc_tgt_offset_high = 3; + dsc->rc_tgt_offset_low = 3; + dsc->simple_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; + + bpp = DSC_BPP(*dsc); + bpc = dsc->bits_per_component; + + ratio_idx = _get_rc_table_index(dsc, scr_ver); + if (ratio_idx == -EINVAL) + return ratio_idx; + + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) + dsc->rc_buf_thresh[i] = sde_dsc_rc_buf_thresh[i]; + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + dsc->rc_range_params[i].range_min_qp = + sde_dsc_rc_range_min_qp[ratio_idx][i]; + dsc->rc_range_params[i].range_max_qp = + sde_dsc_rc_range_max_qp[ratio_idx][i]; + dsc->rc_range_params[i].range_bpg_offset = + sde_dsc_rc_range_bpg_offset[i]; + } + + if (bpp == 8) { + dsc->initial_offset = 6144; + dsc->initial_xmit_delay = 512; + } else if (bpp == 10) { + dsc->initial_offset = 5632; + dsc->initial_xmit_delay = 410; + } else { + dsc->initial_offset = 2048; + dsc->initial_xmit_delay = 341; + } + + dsc->line_buf_depth = bpc + 1; + + if (bpc == 8) { + dsc->flatness_min_qp = 3; + dsc->flatness_max_qp = 12; + dsc->rc_quant_incr_limit0 = 11; + dsc->rc_quant_incr_limit1 = 11; + dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + } else if (bpc == 10) { /* 10bpc */ + dsc->flatness_min_qp = 7; + dsc->flatness_max_qp = 16; + dsc->rc_quant_incr_limit0 = 15; + dsc->rc_quant_incr_limit1 = 15; + dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + } else { /* 12 bpc */ + dsc->flatness_min_qp = 11; + dsc->flatness_max_qp = 20; + dsc->rc_quant_incr_limit0 = 19; + dsc->rc_quant_incr_limit1 = 19; + dsc->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC; + } + if ((dsc->dsc_version_minor == 0x2) && (dsc->native_420)) { + dsc->second_line_bpg_offset = 12; + dsc->second_line_offset_adj = 512; + dsc->nsl_bpg_offset = 2048 * + (DIV_ROUND_UP(dsc->second_line_bpg_offset, + (dsc->slice_height - 1))); + } + + groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); + + dsc->slice_chunk_size = dsc->slice_width * bpp / 8; + if ((dsc->slice_width * bpp) % 8) + dsc->slice_chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * bpp + + groups_per_line * dsc->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); + + dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; + + dsc->initial_scale_value = 8 * dsc->rc_model_size / + (dsc->rc_model_size - dsc->initial_offset); + + slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height; + + groups_total = groups_per_line * dsc->slice_height; + + data = dsc->first_line_bpg_offset * 2048; + + dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); + + pre_num_extra_mux_bits = 3 * (dsc->mux_word_size + (4 * bpc + 4) - 2); + + num_extra_mux_bits = pre_num_extra_mux_bits - (dsc->mux_word_size - + ((slice_bits - pre_num_extra_mux_bits) % dsc->mux_word_size)); + + data = 2048 * (dsc->rc_model_size - dsc->initial_offset + + num_extra_mux_bits); + dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); + + data = dsc->initial_xmit_delay * bpp; + final_value = dsc->rc_model_size - data + num_extra_mux_bits; + + final_scale = 8 * dsc->rc_model_size / + (dsc->rc_model_size - final_value); + + dsc->final_offset = final_value; + + data = (final_scale - 9) * (dsc->nfl_bpg_offset + + dsc->slice_bpg_offset); + dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; + + dsc->scale_decrement_interval = groups_per_line / + (dsc->initial_scale_value - 8); + + return 0; +} + +int sde_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info, + int intf_width) +{ + int mod_offset; + int slice_per_pkt, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + u16 bpp; + + if (!dsc_info || !dsc_info->config.slice_width || + !dsc_info->config.slice_height || + intf_width < dsc_info->config.slice_width) { + SDE_ERROR("invalid input, intf_width=%d slice_width=%d\n", + intf_width, dsc_info ? dsc_info->config.slice_width : + -1); + return -EINVAL; + } + + mod_offset = dsc_info->config.slice_width % 3; + + switch (mod_offset) { + case 0: + dsc_info->slice_last_group_size = 2; + break; + case 1: + dsc_info->slice_last_group_size = 0; + break; + case 2: + dsc_info->slice_last_group_size = 1; + break; + default: + break; + } + + dsc_info->det_thresh_flatness = + 2 << (dsc_info->config.bits_per_component - 8); + + slice_per_pkt = dsc_info->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, + dsc_info->config.slice_width); + + /* + * If slice_per_pkt is greater than slice_per_intf then default to 1. + * This can happen during partial update. + */ + if (slice_per_pkt > slice_per_intf) + slice_per_pkt = 1; + + bpp = DSC_BPP(dsc_info->config); + bytes_in_slice = DIV_ROUND_UP(dsc_info->config.slice_width * + bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc_info->eol_byte_num = total_bytes_per_intf % 3; + dsc_info->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc_info->bytes_in_slice = bytes_in_slice; + dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt; + + return 0; +} + +int sde_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc_info, + char *buf, int pps_id, u32 len) +{ + struct drm_dsc_config *dsc = &dsc_info->config; + char *bp = buf; + char data; + u32 i, bpp; + + if (len < SDE_DSC_PPS_SIZE) + return -EINVAL; + + memset(buf, 0, len); + /* pps0 */ + *bp++ = (dsc->dsc_version_minor | + dsc->dsc_version_major << 4); + *bp++ = (pps_id & 0xff); /* pps1 */ + bp++; /* pps2, reserved */ + + data = dsc->line_buf_depth & 0x0f; + data |= ((dsc->bits_per_component & 0xf) << DSC_PPS_BPC_SHIFT); + *bp++ = data; /* pps3 */ + + bpp = dsc->bits_per_pixel; + data = (bpp >> DSC_PPS_MSB_SHIFT); + data &= 0x03; /* upper two bits */ + data |= ((dsc->block_pred_enable & 0x1) << 5); + data |= ((dsc->convert_rgb & 0x1) << 4); + data |= ((dsc->simple_422 & 0x1) << 3); + data |= ((dsc->vbr_enable & 0x1) << 2); + *bp++ = data; /* pps4 */ + *bp++ = (bpp & DSC_PPS_LSB_MASK); /* pps5 */ + + *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ + *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ + *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ + *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ + + *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ + *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ + *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ + *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ + + *bp++ = ((dsc->slice_chunk_size >> 8) & 0xff);/* pps14 */ + *bp++ = (dsc->slice_chunk_size & 0x0ff); /* pps15 */ + + *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16 */ + *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ + + *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ + *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ + + bp++; /* pps20, reserved */ + + *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ + + *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ + *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ + + *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ + *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ + + bp++; /* pps26, reserved */ + + *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ + + *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ + *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ + *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ + *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ + + *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ + *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ + + *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ + *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ + + *bp++ = (dsc->flatness_min_qp & 0x1f); /* pps36 */ + *bp++ = (dsc->flatness_max_qp & 0x1f); /* pps37 */ + + *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ + *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ + + *bp++ = (dsc->rc_edge_factor & 0x0f); /* pps40 */ + + *bp++ = (dsc->rc_quant_incr_limit0 & 0x1f); /* pps41 */ + *bp++ = (dsc->rc_quant_incr_limit1 & 0x1f); /* pps42 */ + + data = ((dsc->rc_tgt_offset_high & 0xf) << 4); + data |= (dsc->rc_tgt_offset_low & 0x0f); + *bp++ = data; /* pps43 */ + + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) + *bp++ = (dsc->rc_buf_thresh[i] & 0xff); /* pps44 - pps57 */ + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + /* pps58 - pps87 */ + data = (dsc->rc_range_params[i].range_min_qp & 0x1f); + data <<= 3; + data |= ((dsc->rc_range_params[i].range_max_qp >> 2) & 0x07); + *bp++ = data; + data = (dsc->rc_range_params[i].range_max_qp & 0x03); + data <<= 6; + data |= (dsc->rc_range_params[i].range_bpg_offset & 0x3f); + *bp++ = data; + } + + if (dsc->dsc_version_minor == 0x2) { + data = dsc->native_422 | dsc->native_420 << 1; + *bp++ = data; /* pps88 */ + *bp++ = dsc->second_line_bpg_offset; /* pps89 */ + + *bp++ = ((dsc->nsl_bpg_offset >> 8) & 0xff);/* pps90 */ + *bp++ = (dsc->nsl_bpg_offset & 0x0ff); /* pps91 */ + + *bp++ = ((dsc->second_line_offset_adj >> 8) & 0xff); /* pps92*/ + *bp++ = (dsc->second_line_offset_adj & 0x0ff); /* pps93 */ + + /* rest bytes are reserved and set to 0 */ + } + + return 0; +} + diff --git a/msm/sde_dsc_helper.h b/msm/sde_dsc_helper.h new file mode 100644 index 0000000000..b630421064 --- /dev/null +++ b/msm/sde_dsc_helper.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_DSC_HELPER_H__ +#define __SDE_DSC_HELPER_H__ + +#include "msm_drv.h" + +#define DSC_1_1_PPS_PARAMETER_SET_ELEMENTS 88 + +int sde_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver); + +int sde_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info, + int intf_width); + +int sde_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc_info, + char *buf, int pps_id, u32 len); + +#endif /* __SDE_DSC_HELPER_H__ */ +