diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules')
9 files changed, 279 insertions, 95 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index b8695660b480..5c67e12b2e55 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -30,6 +30,14 @@ #include "opp.h" #include "color_gamma.h" +/* When calculating LUT values the first region and at least one subsequent + * region are calculated with full precision. These defines are a demarcation + * of where the second region starts and ends. + * These are hardcoded values to avoid recalculating them in loops. + */ +#define PRECISE_LUT_REGION_START 224 +#define PRECISE_LUT_REGION_END 239 + static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; // these are helpers for calculations to reduce stack usage @@ -151,7 +159,7 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1)); base2 = dc_fixpt_div(base, div); - //avoid complex numbers + // avoid complex numbers if (dc_fixpt_lt(base2, dc_fixpt_zero)) base2 = dc_fixpt_sub(dc_fixpt_zero, base2); @@ -161,7 +169,7 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) } -/*de gamma, none linear to linear*/ +/* de gamma, non-linear to linear */ static void compute_hlg_eotf(struct fixed31_32 in_x, struct fixed31_32 *out_y, uint32_t sdr_white_level, uint32_t max_luminance_nits) @@ -193,7 +201,7 @@ static void compute_hlg_eotf(struct fixed31_32 in_x, } -/*re gamma, linear to none linear*/ +/* re gamma, linear to non-linear */ static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y, uint32_t sdr_white_level, uint32_t max_luminance_nits) { @@ -346,7 +354,13 @@ static struct fixed31_32 translate_from_linear_space( dc_fixpt_recip(args->gamma)); } scratch_1 = dc_fixpt_add(one, args->a3); - if (cal_buffer->buffer_index < 16) + /* In the first region (first 16 points) and in the + * region delimited by START/END we calculate with + * full precision to avoid error accumulation. + */ + if ((cal_buffer->buffer_index >= PRECISE_LUT_REGION_START && + cal_buffer->buffer_index <= PRECISE_LUT_REGION_END) || + (cal_buffer->buffer_index < 16)) scratch_2 = dc_fixpt_pow(args->arg, dc_fixpt_recip(args->gamma)); else @@ -397,9 +411,7 @@ static struct fixed31_32 translate_from_linear_space_long( dc_fixpt_recip(args->gamma))), args->a2); else - return dc_fixpt_mul( - args->arg, - args->a1); + return dc_fixpt_mul(args->arg, args->a1); } static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg, bool use_eetf, struct calculate_buffer *cal_buffer) @@ -717,7 +729,6 @@ static struct fixed31_32 calculate_mapped_value( BREAK_TO_DEBUGGER(); result = dc_fixpt_zero; } else { - BREAK_TO_DEBUGGER(); result = dc_fixpt_one; } @@ -830,7 +841,7 @@ static bool build_regamma(struct pwl_float_data_ex *rgb_regamma, i = 0; while (i <= hw_points_num) { - /*TODO use y vs r,g,b*/ + /* TODO use y vs r,g,b */ rgb->r = translate_from_linear_space_ex( coord_x->x, coeff, 0, cal_buffer); rgb->g = rgb->r; @@ -937,6 +948,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, uint32_t i; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; + const struct hw_x_point *prv_coord_x = coord_x; struct fixed31_32 scaledX = dc_fixpt_zero; struct fixed31_32 scaledX1 = dc_fixpt_zero; struct fixed31_32 max_display; @@ -947,6 +959,9 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, bool use_eetf = false; bool is_clipped = false; struct fixed31_32 sdr_white_level; + struct fixed31_32 coordX_diff; + struct fixed31_32 out_dist_max; + struct fixed31_32 bright_norm; if (fs_params->max_content == 0 || fs_params->max_display == 0) @@ -972,10 +987,11 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, cal_buffer->buffer_index = 0; // see var definition for more info rgb += 32; // first 32 points have problems with fixed point, too small coord_x += 32; + for (i = 32; i <= hw_points_num; i++) { if (!is_clipped) { if (use_eetf) { - /*max content is equal 1 */ + /* max content is equal 1 */ scaledX1 = dc_fixpt_div(coord_x->x, dc_fixpt_div(max_content, sdr_white_level)); hermite_spline_eetf(scaledX1, max_display, min_display, @@ -990,21 +1006,65 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, else output = calculate_gamma22(scaledX, use_eetf, cal_buffer); + // Ensure output respects reasonable boundaries + output = dc_fixpt_clamp(output, dc_fixpt_zero, dc_fixpt_one); + rgb->r = output; rgb->g = output; rgb->b = output; } else { + /* Here clipping happens for the first time */ is_clipped = true; - rgb->r = clip; - rgb->g = clip; - rgb->b = clip; + + /* The next few lines implement the equation + * output = prev_out + + * (coord_x->x - prev_coord_x->x) * + * (1.0 - prev_out) / + * (maxDisp/sdr_white_level - prevCoordX) + * + * This equation interpolates the first point + * after max_display/80 so that the slope from + * hw_x_before_max and hw_x_after_max is such + * that we hit Y=1.0 at max_display/80. + */ + + coordX_diff = dc_fixpt_sub(coord_x->x, prv_coord_x->x); + out_dist_max = dc_fixpt_sub(dc_fixpt_one, output); + bright_norm = dc_fixpt_div(max_display, sdr_white_level); + + output = dc_fixpt_add( + output, dc_fixpt_mul( + coordX_diff, dc_fixpt_div( + out_dist_max, + dc_fixpt_sub(bright_norm, prv_coord_x->x) + ) + ) + ); + + /* Relaxing the maximum boundary to 1.07 (instead of 1.0) + * because the last point in the curve must be such that + * the maximum display pixel brightness interpolates to + * exactly 1.0. The worst case scenario was calculated + * around 1.057, so the limit of 1.07 leaves some safety + * margin. + */ + output = dc_fixpt_clamp(output, dc_fixpt_zero, + dc_fixpt_from_fraction(107, 100)); + + rgb->r = output; + rgb->g = output; + rgb->b = output; } } else { + /* Every other clipping after the first + * one is dealt with here + */ rgb->r = clip; rgb->g = clip; rgb->b = clip; } + prv_coord_x = coord_x; ++coord_x; ++rgb; } @@ -1073,7 +1133,7 @@ static void build_hlg_degamma(struct pwl_float_data_ex *degamma, const struct hw_x_point *coord_x = coordinate_x; i = 0; - //check when i == 434 + // check when i == 434 while (i != hw_points_num + 1) { compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; @@ -1097,7 +1157,7 @@ static void build_hlg_regamma(struct pwl_float_data_ex *regamma, i = 0; - //when i == 471 + // when i == 471 while (i != hw_points_num + 1) { compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; @@ -1331,6 +1391,8 @@ static void apply_lut_1d( struct fixed31_32 lut1; struct fixed31_32 lut2; const int max_lut_index = 4095; + const struct fixed31_32 penult_lut_index_f = + dc_fixpt_from_int(max_lut_index-1); const struct fixed31_32 max_lut_index_f = dc_fixpt_from_int(max_lut_index); int32_t index = 0, index_next = 0; @@ -1355,10 +1417,21 @@ static void apply_lut_1d( index = dc_fixpt_floor(norm_y); index_f = dc_fixpt_from_int(index); - if (index < 0 || index > max_lut_index) + if (index < 0) continue; - index_next = (index == max_lut_index) ? index : index+1; + if (index <= max_lut_index) + index_next = (index == max_lut_index) ? index : index+1; + else { + /* Here we are dealing with the last point in the curve, + * which in some cases might exceed the range given by + * max_lut_index. So we interpolate the value using + * max_lut_index and max_lut_index - 1. + */ + index = max_lut_index - 1; + index_next = max_lut_index; + index_f = penult_lut_index_f; + } if (color == 0) { lut1 = ramp->entries.red[index]; @@ -1586,9 +1659,7 @@ static void build_new_custom_resulted_curve( uint32_t hw_points_num, struct dc_transfer_func_distributed_points *tf_pts) { - uint32_t i; - - i = 0; + uint32_t i = 0; while (i != hw_points_num + 1) { tf_pts->red[i] = dc_fixpt_clamp( @@ -1614,7 +1685,7 @@ static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinates_x; - build_coefficients(&coeff, true); + build_coefficients(&coeff, TRANSFER_FUNCTION_SRGB); i = 0; while (i != hw_points_num + 1) { @@ -1637,7 +1708,8 @@ static bool map_regamma_hw_to_x_user( const struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, struct dc_transfer_func_distributed_points *tf_pts, - bool mapUserRamp) + bool mapUserRamp, + bool doClamping) { /* setup to spare calculated ideal regamma values */ @@ -1665,8 +1737,10 @@ static bool map_regamma_hw_to_x_user( } } - /* this should be named differently, all it does is clamp to 0-1 */ - build_new_custom_resulted_curve(hw_points_num, tf_pts); + if (doClamping) { + /* this should be named differently, all it does is clamp to 0-1 */ + build_new_custom_resulted_curve(hw_points_num, tf_pts); + } return true; } @@ -1675,7 +1749,8 @@ static bool map_regamma_hw_to_x_user( bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer) + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp) { struct gamma_coefficients coeff; const struct hw_x_point *coord_x = coordinates_x; @@ -1716,6 +1791,9 @@ bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, ++i; } + if (ramp && ramp->type == GAMMA_CS_TFM_1D) + apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); + // this function just clamps output to 0-1 build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts); output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; @@ -1725,7 +1803,8 @@ bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer) + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp) { struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; struct dividers dividers; @@ -1772,6 +1851,9 @@ bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, tf_pts->x_point_at_y1_green = 1; tf_pts->x_point_at_y1_blue = 1; + if (ramp && ramp->type == GAMMA_CS_TFM_1D) + apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); + // this function just clamps output to 0-1 build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts); @@ -1914,11 +1996,12 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, ++i; } } else { - //clamps to 0-1 + // clamps to 0-1 map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); + mapUserRamp && ramp && ramp->type == GAMMA_RGB_256, + true); } @@ -2034,6 +2117,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, struct gamma_pixel *axis_x = NULL; struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + bool doClamping = true; bool ret = false; if (output_tf->type == TF_TYPE_BYPASS) @@ -2100,11 +2184,15 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, cal_buffer); if (ret) { + doClamping = !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 && + fs_params != NULL && fs_params->skip_tm == 0); + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, rgb_regamma, MAX_HW_POINTS, tf_pts, (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) && - (ramp && ramp->type != GAMMA_CS_TFM_1D)); + (ramp && ramp->type != GAMMA_CS_TFM_1D), + doClamping); if (ramp && ramp->type == GAMMA_CS_TFM_1D) apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h index 37ffbef6602b..7563457e2ff4 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -120,11 +120,13 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer); + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp); bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer); + struct calculate_buffer *cal_buffer, + const struct dc_gamma *ramp); #endif /* COLOR_MOD_COLOR_GAMMA_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index d988533d4af5..4762273b5bb9 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -41,11 +41,11 @@ #define BTR_MAX_MARGIN 2500 /* Threshold to change BTR multiplier (to avoid frequent changes) */ #define BTR_DRIFT_MARGIN 2000 -/*Threshold to exit fixed refresh rate*/ -#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4 -/* Number of consecutive frames to check before entering/exiting fixed refresh*/ +/* Threshold to exit fixed refresh rate */ +#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1 +/* Number of consecutive frames to check before entering/exiting fixed refresh */ #define FIXED_REFRESH_ENTER_FRAME_COUNT 5 -#define FIXED_REFRESH_EXIT_FRAME_COUNT 5 +#define FIXED_REFRESH_EXIT_FRAME_COUNT 10 struct core_freesync { struct mod_freesync public; @@ -85,7 +85,7 @@ void mod_freesync_destroy(struct mod_freesync *mod_freesync) kfree(core_freesync); } -#if 0 /* unused currently */ +#if 0 /* Unused currently */ static unsigned int calc_refresh_in_uhz_from_duration( unsigned int duration_in_ns) { @@ -184,7 +184,7 @@ static void update_v_total_for_static_ramp( bool ramp_direction_is_up = (current_duration_in_us > target_duration_in_us) ? true : false; - /* Calc ratio between new and current frame duration with 3 digit */ + /* Calculate ratio between new and current frame duration with 3 digit */ unsigned int frame_duration_ratio = div64_u64(1000000, (1000 + div64_u64(((unsigned long long)( STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * @@ -204,10 +204,10 @@ static void update_v_total_for_static_ramp( /* Going to a higher refresh rate (lower frame duration) */ if (ramp_direction_is_up) { - /* reduce frame duration */ + /* Reduce frame duration */ current_duration_in_us -= ramp_rate_interpolated; - /* adjust for frame duration below min */ + /* Adjust for frame duration below min */ if (current_duration_in_us <= target_duration_in_us) { in_out_vrr->fixed.ramping_active = false; in_out_vrr->fixed.ramping_done = true; @@ -217,10 +217,10 @@ static void update_v_total_for_static_ramp( } /* Going to a lower refresh rate (larger frame duration) */ } else { - /* increase frame duration */ + /* Increase frame duration */ current_duration_in_us += ramp_rate_interpolated; - /* adjust for frame duration above max */ + /* Adjust for frame duration above max */ if (current_duration_in_us >= target_duration_in_us) { in_out_vrr->fixed.ramping_active = false; in_out_vrr->fixed.ramping_done = true; @@ -289,7 +289,7 @@ static void apply_below_the_range(struct core_freesync *core_freesync, } else { /* Calculate number of midPoint frames that could fit within - * the render time interval- take ceil of this value + * the render time interval - take ceil of this value */ mid_point_frames_ceil = (last_render_time_in_us + in_out_vrr->btr.mid_point_in_us - 1) / @@ -306,7 +306,7 @@ static void apply_below_the_range(struct core_freesync *core_freesync, } /* Calculate number of midPoint frames that could fit within - * the render time interval- take floor of this value + * the render time interval - take floor of this value */ mid_point_frames_floor = last_render_time_in_us / in_out_vrr->btr.mid_point_in_us; @@ -420,7 +420,8 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, in_out_vrr->fixed.target_refresh_in_uhz = 0; update = true; } - } + } else + in_out_vrr->fixed.frame_counter = 0; } else if (last_render_time_in_us > max_render_time_in_us) { /* Enter Fixed Refresh mode */ if (!in_out_vrr->fixed.fixed_active) { @@ -434,7 +435,8 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, in_out_vrr->max_refresh_in_uhz; update = true; } - } + } else + in_out_vrr->fixed.frame_counter = 0; } if (update) { @@ -559,7 +561,7 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, */ infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); - //FreeSync HDR + /* FreeSync HDR */ infopacket->sb[9] = 0; infopacket->sb[10] = 0; } @@ -567,6 +569,12 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr, struct dc_info_packet *infopacket) { + unsigned int min_refresh; + unsigned int max_refresh; + unsigned int fixed_refresh; + unsigned int min_programmed; + unsigned int max_programmed; + /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ infopacket->sb[1] = 0x1A; @@ -596,23 +604,33 @@ static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr, vrr->state == VRR_STATE_ACTIVE_FIXED) infopacket->sb[6] |= 0x04; - if (vrr->state == VRR_STATE_ACTIVE_FIXED) { - /* PB7 = FreeSync Minimum refresh rate (Hz) */ - infopacket->sb[7] = (unsigned char)((vrr->fixed_refresh_in_uhz + 500000) / 1000000); - /* PB8 = FreeSync Maximum refresh rate (Hz) */ - infopacket->sb[8] = (unsigned char)((vrr->fixed_refresh_in_uhz + 500000) / 1000000); - } else if (vrr->state == VRR_STATE_ACTIVE_VARIABLE) { - /* PB7 = FreeSync Minimum refresh rate (Hz) */ - infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000); - /* PB8 = FreeSync Maximum refresh rate (Hz) */ - infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); - } else { - // Non-fs case, program nominal range - /* PB7 = FreeSync Minimum refresh rate (Hz) */ - infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); - /* PB8 = FreeSync Maximum refresh rate (Hz) */ - infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); - } + min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000; + max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000; + fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000; + + min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh : + (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh : + (vrr->state == VRR_STATE_INACTIVE) ? min_refresh : + max_refresh; // Non-fs case, program nominal range + + max_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh : + (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? max_refresh : + max_refresh;// Non-fs case, program nominal range + + /* PB7 = FreeSync Minimum refresh rate (Hz) */ + infopacket->sb[7] = min_programmed & 0xFF; + + /* PB8 = FreeSync Maximum refresh rate (Hz) */ + infopacket->sb[8] = max_programmed & 0xFF; + + /* PB11 : MSB FreeSync Minimum refresh rate [Hz] - bits 9:8 */ + infopacket->sb[11] = (min_programmed >> 8) & 0x03; + + /* PB12 : MSB FreeSync Maximum refresh rate [Hz] - bits 9:8 */ + infopacket->sb[12] = (max_programmed >> 8) & 0x03; + + /* PB16 : Reserved bits 7:1, FixedRate bit 0 */ + infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0; //FreeSync HDR infopacket->sb[9] = 0; @@ -731,6 +749,58 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal, } } +static void build_vrr_infopacket_header_v3(enum signal_type signal, + struct dc_info_packet *infopacket, + unsigned int *payload_size) +{ + unsigned char version; + + version = 3; + if (dc_is_hdmi_signal(signal)) { + + /* HEADER */ + + /* HB0 = Packet Type = 0x83 (Source Product + * Descriptor InfoFrame) + */ + infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; + + /* HB1 = Version = 0x03 */ + infopacket->hb1 = version; + + /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length] */ + *payload_size = 0x10; + infopacket->hb2 = *payload_size - 1; //-1 for checksum + + } else if (dc_is_dp_signal(signal)) { + + /* HEADER */ + + /* HB0 = Secondary-data Packet ID = 0 - Only non-zero + * when used to associate audio related info packets + */ + infopacket->hb0 = 0x00; + + /* HB1 = Packet Type = 0x83 (Source Product + * Descriptor InfoFrame) + */ + infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; + + /* HB2 = [Bits 7:0 = Least significant eight bits - + * For INFOFRAME, the value must be 1Bh] + */ + infopacket->hb2 = 0x1B; + + /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2] + * [Bits 1:0 = Most significant two bits = 0x00] + */ + + infopacket->hb3 = (version & 0x3F) << 2; + + *payload_size = 0x1B; + } +} + static void build_vrr_infopacket_checksum(unsigned int *payload_size, struct dc_info_packet *infopacket) { @@ -816,7 +886,7 @@ static void build_vrr_infopacket_v3(enum signal_type signal, { unsigned int payload_size = 0; - build_vrr_infopacket_header_v2(signal, infopacket, &payload_size); + build_vrr_infopacket_header_v3(signal, infopacket, &payload_size); build_vrr_infopacket_data_v3(vrr, infopacket); build_vrr_infopacket_fs2_data(app_tf, infopacket); @@ -897,15 +967,15 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, min_refresh_in_uhz = in_config->min_refresh_in_uhz; max_refresh_in_uhz = in_config->max_refresh_in_uhz; - // Full range may be larger than current video timing, so cap at nominal + /* Full range may be larger than current video timing, so cap at nominal */ if (max_refresh_in_uhz > nominal_field_rate_in_uhz) max_refresh_in_uhz = nominal_field_rate_in_uhz; - // Full range may be larger than current video timing, so cap at nominal + /* Full range may be larger than current video timing, so cap at nominal */ if (min_refresh_in_uhz > max_refresh_in_uhz) min_refresh_in_uhz = max_refresh_in_uhz; - // If a monitor reports exactly max refresh of 2x of min, enforce it on nominal + /* If a monitor reports exactly max refresh of 2x of min, enforce it on nominal */ rounded_nominal_in_uhz = div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000; if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) && @@ -1042,7 +1112,7 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, last_render_time_in_us = curr_time_stamp_in_us - plane->time.prev_update_time_in_us; - // Sum off all entries except oldest one + /* Sum off all entries except oldest one */ for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) { average_render_time_in_us += plane->time.time_elapsed_in_us[i]; @@ -1050,7 +1120,7 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, average_render_time_in_us -= plane->time.time_elapsed_in_us[oldest_index]; - // Add render time for current flip + /* Add render time for current flip */ average_render_time_in_us += last_render_time_in_us; average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX; @@ -1125,8 +1195,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) in_out_vrr->fixed.ramping_active = false; - /* Gradual Static Screen Ramping Logic */ - /* Execute if ramp is active and user enabled freesync static screen*/ + /* Gradual Static Screen Ramping Logic + * Execute if ramp is active and user enabled freesync static screen + */ if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED && in_out_vrr->fixed.ramping_active) { update_v_total_for_static_ramp( @@ -1214,20 +1285,20 @@ bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz, min_refresh_cap_in_uhz /= 1000000; max_refresh_cap_in_uhz /= 1000000; - // Check nominal is within range + /* Check nominal is within range */ if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || nominal_field_rate_in_uhz < min_refresh_cap_in_uhz) return false; - // If nominal is less than max, limit the max allowed refresh rate + /* If nominal is less than max, limit the max allowed refresh rate */ if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; - // Check min is within range + /* Check min is within range */ if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz) return false; - // For variable range, check for at least 10 Hz range + /* For variable range, check for at least 10 Hz range */ if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10) return false; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c index f244b72e74e0..73ca49f05bd3 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c @@ -128,8 +128,12 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp) static inline enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) { - /* device count must be greater than or equal to tracked hdcp displays */ - return (get_device_count(hdcp) < get_active_display_count(hdcp)) ? + /* Some MST display may choose to report the internal panel as an HDCP RX. + * To update this condition with 1(because the immediate repeater's internal + * panel is possibly not included in DEVICE_COUNT) + get_device_count(hdcp). + * Device count must be greater than or equal to tracked hdcp displays. + */ + return ((1 + get_device_count(hdcp)) < get_active_display_count(hdcp)) ? MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE : MOD_HDCP_STATUS_SUCCESS; } diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_transition.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_transition.c index f3711914364e..24ab95b093f7 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_transition.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_transition.c @@ -231,7 +231,7 @@ enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp, fail_and_restart_in_ms(0, &status, output); break; } else if (conn->hdcp1_retry_count < conn->link.adjust.hdcp1.min_auth_retries_wa) { - fail_and_restart_in_ms(0, &status, output); + fail_and_restart_in_ms(200, &status, output); break; } if (conn->is_repeater) { diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c index 549c113abcf7..a0895a7efda2 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c @@ -207,8 +207,11 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp) static enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) { - /* device count must be greater than or equal to tracked hdcp displays */ - return (get_device_count(hdcp) < get_active_display_count(hdcp)) ? + /* Some MST display may choose to report the internal panel as an HDCP RX. */ + /* To update this condition with 1(because the immediate repeater's internal */ + /* panel is possibly not included in DEVICE_COUNT) + get_device_count(hdcp). */ + /* Device count must be greater than or equal to tracked hdcp displays. */ + return ((1 + get_device_count(hdcp)) < get_active_display_count(hdcp)) ? MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE : MOD_HDCP_STATUS_SUCCESS; } diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c index fb6a19d020f9..ee5230ccf3c4 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c @@ -280,6 +280,6 @@ char *mod_hdcp_state_id_to_str(int32_t id) return "D2_A9_VALIDATE_STREAM_READY"; default: return "UNKNOWN_STATE_ID"; - }; + } } diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 61497954e67e..4fd8bce95d84 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -82,22 +82,24 @@ struct abm_parameters { unsigned char deviation_gain; unsigned char min_knee; unsigned char max_knee; + unsigned short blRampReduction; + unsigned short blRampStart; }; static const struct abm_parameters abm_settings_config0[abm_defines_max_level] = { -// min_red max_red bright_pos dark_pos brightness_gain contrast deviation min_knee max_knee - {0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xe0}, - {0xde, 0x85, 0x20, 0x00, 0xff, 0x90, 0xa8, 0x40, 0xdf}, - {0xb0, 0x50, 0x20, 0x00, 0xc0, 0x88, 0x78, 0x70, 0xa0}, - {0x82, 0x40, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70}, +// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blStart blRed + {0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xe0, 0xCCCC, 0xCCCC}, + {0xde, 0x85, 0x20, 0x00, 0xff, 0x90, 0xa8, 0x40, 0xdf, 0xCCCC, 0xCCCC}, + {0xb0, 0x50, 0x20, 0x00, 0xc0, 0x88, 0x78, 0x70, 0xa0, 0xCCCC, 0xCCCC}, + {0x82, 0x40, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, }; static const struct abm_parameters abm_settings_config1[abm_defines_max_level] = { -// min_red max_red bright_pos dark_pos brightness_gain contrast deviation min_knee max_knee - {0xf0, 0xd9, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70}, - {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70}, - {0x99, 0x65, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70}, - {0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70}, +// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blStart blRed + {0xf0, 0xd9, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, + {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, + {0x99, 0x65, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xCCCC, 0xCCCC}, }; static const struct abm_parameters * const abm_settings[] = { @@ -662,10 +664,11 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, { struct iram_table_v_2_2 ram_table; struct abm_config_table config; + unsigned int set = params.set; bool result = false; uint32_t i, j = 0; -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (res_pool->abm == NULL && res_pool->multiple_abms[0] == NULL) return false; #else @@ -710,13 +713,25 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, config.max_knee[i] = ram_table.max_knee[i]; } + if (params.backlight_ramping_override) { + for (i = 0; i < NUM_AGGR_LEVEL; i++) { + config.blRampReduction[i] = params.backlight_ramping_reduction; + config.blRampStart[i] = params.backlight_ramping_start; + } + } else { + for (i = 0; i < NUM_AGGR_LEVEL; i++) { + config.blRampReduction[i] = abm_settings[set][i].blRampReduction; + config.blRampStart[i] = abm_settings[set][i].blRampStart; + } + } + config.min_abm_backlight = ram_table.min_abm_backlight; -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) - if (res_pool->multiple_abms[0]) { +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (res_pool->multiple_abms[0]) result = res_pool->multiple_abms[0]->funcs->init_abm_config( res_pool->multiple_abms[0], (char *)(&config), sizeof(struct abm_config_table)); - } else + else #endif result = res_pool->abm->funcs->init_abm_config( res_pool->abm, (char *)(&config), sizeof(struct abm_config_table)); diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index fa4728d88092..6f2eecce6baa 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -39,6 +39,7 @@ enum abm_defines { struct dmcu_iram_parameters { unsigned int *backlight_lut_array; unsigned int backlight_lut_array_size; + bool backlight_ramping_override; unsigned int backlight_ramping_reduction; unsigned int backlight_ramping_start; unsigned int min_abm_backlight; |