diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules')
7 files changed, 498 insertions, 376 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 88898935a5e6..2d8f14b69117 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -30,7 +30,6 @@ #include "opp.h" #include "color_gamma.h" - #define NUM_PTS_IN_REGION 16 #define NUM_REGIONS 32 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS) @@ -40,6 +39,33 @@ static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2]; +// these are helpers for calculations to reduce stack usage +// do not depend on these being preserved across calls +static struct fixed31_32 scratch_1; +static struct fixed31_32 scratch_2; +static struct translate_from_linear_space_args scratch_gamma_args; + +/* Helper to optimize gamma calculation, only use in translate_from_linear, in + * particular the dc_fixpt_pow function which is very expensive + * The idea is that our regions for X points are exponential and currently they all use + * the same number of points (NUM_PTS_IN_REGION) and in each region every point + * is exactly 2x the one at the same index in the previous region. In other words + * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16 + * The other fact is that (2x)^gamma = 2^gamma * x^gamma + * So we compute and save x^gamma for the first 16 regions, and for every next region + * just multiply with 2^gamma which can be computed once, and save the result so we + * recursively compute all the values. + */ +static struct fixed31_32 pow_buffer[NUM_PTS_IN_REGION]; +static struct fixed31_32 gamma_of_2; // 2^gamma +int pow_buffer_ptr = -1; + /*sRGB 709 2.2 2.4 P3*/ +static const int32_t gamma_numerator01[] = { 31308, 180000, 0, 0, 0}; +static const int32_t gamma_numerator02[] = { 12920, 4500, 0, 0, 0}; +static const int32_t gamma_numerator03[] = { 55, 99, 0, 0, 0}; +static const int32_t gamma_numerator04[] = { 55, 99, 0, 0, 0}; +static const int32_t gamma_numerator05[] = { 2400, 2200, 2200, 2400, 2600}; + static bool pq_initialized; /* = false; */ static bool de_pq_initialized; /* = false; */ @@ -71,6 +97,18 @@ void setup_x_points_distribution(void) } } +void log_x_points_distribution(struct dal_logger *logger) +{ + int i = 0; + + if (logger != NULL) { + LOG_GAMMA_WRITE("Log X Distribution\n"); + + for (i = 0; i < MAX_HW_POINTS; i++) + LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value); + } +} + static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) { /* consts for PQ gamma formula. */ @@ -135,59 +173,68 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) } + /*de gamma, none linear to linear*/ -static void compute_hlg_oetf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +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) { struct fixed31_32 a; struct fixed31_32 b; struct fixed31_32 c; struct fixed31_32 threshold; - struct fixed31_32 reference_white_level; + struct fixed31_32 x; + struct fixed31_32 scaling_factor = + dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level); a = dc_fixpt_from_fraction(17883277, 100000000); - if (is_light0_12) { - /*light 0-12*/ - b = dc_fixpt_from_fraction(28466892, 100000000); - c = dc_fixpt_from_fraction(55991073, 100000000); - threshold = dc_fixpt_one; - reference_white_level = dc_fixpt_half; + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + threshold = dc_fixpt_from_fraction(1, 2); + + if (dc_fixpt_lt(in_x, threshold)) { + x = dc_fixpt_mul(in_x, in_x); + x = dc_fixpt_div_int(x, 3); } else { - /*light 0-1*/ - b = dc_fixpt_from_fraction(2372241, 100000000); - c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); - threshold = dc_fixpt_from_fraction(1, 12); - reference_white_level = dc_fixpt_pow(dc_fixpt_from_fraction(3, 1), dc_fixpt_half); + x = dc_fixpt_sub(in_x, c); + x = dc_fixpt_div(x, a); + x = dc_fixpt_exp(x); + x = dc_fixpt_add(x, b); + x = dc_fixpt_div_int(x, 12); } - if (dc_fixpt_lt(threshold, in_x)) - *out_y = dc_fixpt_add(c, dc_fixpt_mul(a, dc_fixpt_log(dc_fixpt_sub(in_x, b)))); - else - *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_half), reference_white_level); + *out_y = dc_fixpt_mul(x, scaling_factor); + } /*re gamma, linear to none linear*/ -static void compute_hlg_eotf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +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) { struct fixed31_32 a; struct fixed31_32 b; struct fixed31_32 c; - struct fixed31_32 reference_white_level; + struct fixed31_32 threshold; + struct fixed31_32 x; + struct fixed31_32 scaling_factor = + dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits); a = dc_fixpt_from_fraction(17883277, 100000000); - if (is_light0_12) { - /*light 0-12*/ - b = dc_fixpt_from_fraction(28466892, 100000000); - c = dc_fixpt_from_fraction(55991073, 100000000); - reference_white_level = dc_fixpt_from_fraction(4, 1); + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + threshold = dc_fixpt_from_fraction(1, 12); + x = dc_fixpt_mul(in_x, scaling_factor); + + + if (dc_fixpt_lt(x, threshold)) { + x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1)); + *out_y = dc_fixpt_pow(x, dc_fixpt_half); } else { - /*light 0-1*/ - b = dc_fixpt_from_fraction(2372241, 100000000); - c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); - reference_white_level = dc_fixpt_from_fraction(1, 3); + x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1)); + x = dc_fixpt_sub(x, b); + x = dc_fixpt_log(x); + x = dc_fixpt_mul(a, x); + *out_y = dc_fixpt_add(x, c); } - if (dc_fixpt_lt(dc_fixpt_half, in_x)) - *out_y = dc_fixpt_add(dc_fixpt_exp(dc_fixpt_div(dc_fixpt_sub(in_x, c), a)), b); - else - *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_from_fraction(2, 1)), reference_white_level); } @@ -243,93 +290,101 @@ struct dividers { struct fixed31_32 divider3; }; -enum gamma_type_index { - gamma_type_index_2_4, - gamma_type_index_2_2, - gamma_type_index_2_2_flat -}; -static void build_coefficients(struct gamma_coefficients *coefficients, enum gamma_type_index type) +static bool build_coefficients(struct gamma_coefficients *coefficients, enum dc_transfer_func_predefined type) { - static const int32_t numerator01[] = { 31308, 180000, 0}; - static const int32_t numerator02[] = { 12920, 4500, 0}; - static const int32_t numerator03[] = { 55, 99, 0}; - static const int32_t numerator04[] = { 55, 99, 0}; - static const int32_t numerator05[] = { 2400, 2200, 2200}; uint32_t i = 0; uint32_t index = 0; + bool ret = true; - if (type == gamma_type_index_2_2) + if (type == TRANSFER_FUNCTION_SRGB) + index = 0; + else if (type == TRANSFER_FUNCTION_BT709) index = 1; - else if (type == gamma_type_index_2_2_flat) + else if (type == TRANSFER_FUNCTION_GAMMA22) index = 2; + else if (type == TRANSFER_FUNCTION_GAMMA24) + index = 3; + else if (type == TRANSFER_FUNCTION_GAMMA26) + index = 4; + else { + ret = false; + goto release; + } do { coefficients->a0[i] = dc_fixpt_from_fraction( - numerator01[index], 10000000); + gamma_numerator01[index], 10000000); coefficients->a1[i] = dc_fixpt_from_fraction( - numerator02[index], 1000); + gamma_numerator02[index], 1000); coefficients->a2[i] = dc_fixpt_from_fraction( - numerator03[index], 1000); + gamma_numerator03[index], 1000); coefficients->a3[i] = dc_fixpt_from_fraction( - numerator04[index], 1000); + gamma_numerator04[index], 1000); coefficients->user_gamma[i] = dc_fixpt_from_fraction( - numerator05[index], 1000); + gamma_numerator05[index], 1000); ++i; } while (i != ARRAY_SIZE(coefficients->a0)); +release: + return ret; } static struct fixed31_32 translate_from_linear_space( - struct fixed31_32 arg, - struct fixed31_32 a0, - struct fixed31_32 a1, - struct fixed31_32 a2, - struct fixed31_32 a3, - struct fixed31_32 gamma) + struct translate_from_linear_space_args *args) { const struct fixed31_32 one = dc_fixpt_from_int(1); - if (dc_fixpt_lt(one, arg)) + if (dc_fixpt_le(one, args->arg)) return one; - if (dc_fixpt_le(arg, dc_fixpt_neg(a0))) - return dc_fixpt_sub( - a2, - dc_fixpt_mul( - dc_fixpt_add( - one, - a3), - dc_fixpt_pow( - dc_fixpt_neg(arg), - dc_fixpt_recip(gamma)))); - else if (dc_fixpt_le(a0, arg)) - return dc_fixpt_sub( - dc_fixpt_mul( - dc_fixpt_add( - one, - a3), - dc_fixpt_pow( - arg, - dc_fixpt_recip(gamma))), - a2); + if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) { + scratch_1 = dc_fixpt_add(one, args->a3); + scratch_2 = dc_fixpt_pow( + dc_fixpt_neg(args->arg), + dc_fixpt_recip(args->gamma)); + scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); + scratch_1 = dc_fixpt_sub(args->a2, scratch_1); + + return scratch_1; + } else if (dc_fixpt_le(args->a0, args->arg)) { + if (pow_buffer_ptr == 0) { + gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_recip(args->gamma)); + } + scratch_1 = dc_fixpt_add(one, args->a3); + if (pow_buffer_ptr < 16) + scratch_2 = dc_fixpt_pow(args->arg, + dc_fixpt_recip(args->gamma)); + else + scratch_2 = dc_fixpt_mul(gamma_of_2, + pow_buffer[pow_buffer_ptr%16]); + + pow_buffer[pow_buffer_ptr%16] = scratch_2; + pow_buffer_ptr++; + + scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); + scratch_1 = dc_fixpt_sub(scratch_1, args->a2); + + return scratch_1; + } else - return dc_fixpt_mul( - arg, - a1); + return dc_fixpt_mul(args->arg, args->a1); } static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg) { struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10); - return translate_from_linear_space(arg, - dc_fixpt_zero, - dc_fixpt_zero, - dc_fixpt_zero, - dc_fixpt_zero, - gamma); + scratch_gamma_args.arg = arg; + scratch_gamma_args.a0 = dc_fixpt_zero; + scratch_gamma_args.a1 = dc_fixpt_zero; + scratch_gamma_args.a2 = dc_fixpt_zero; + scratch_gamma_args.a3 = dc_fixpt_zero; + scratch_gamma_args.gamma = gamma; + + return translate_from_linear_space(&scratch_gamma_args); } static struct fixed31_32 translate_to_linear_space( @@ -365,18 +420,19 @@ static struct fixed31_32 translate_to_linear_space( return linear; } -static inline struct fixed31_32 translate_from_linear_space_ex( +static struct fixed31_32 translate_from_linear_space_ex( struct fixed31_32 arg, struct gamma_coefficients *coeff, uint32_t color_index) { - return translate_from_linear_space( - arg, - coeff->a0[color_index], - coeff->a1[color_index], - coeff->a2[color_index], - coeff->a3[color_index], - coeff->user_gamma[color_index]); + scratch_gamma_args.arg = arg; + scratch_gamma_args.a0 = coeff->a0[color_index]; + scratch_gamma_args.a1 = coeff->a1[color_index]; + scratch_gamma_args.a2 = coeff->a2[color_index]; + scratch_gamma_args.a3 = coeff->a3[color_index]; + scratch_gamma_args.gamma = coeff->user_gamma[color_index]; + + return translate_from_linear_space(&scratch_gamma_args); } @@ -709,30 +765,42 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, } } -static void build_regamma(struct pwl_float_data_ex *rgb_regamma, +static bool build_regamma(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, enum gamma_type_index type) + const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) { uint32_t i; + bool ret = false; - struct gamma_coefficients coeff; + struct gamma_coefficients *coeff; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; - build_coefficients(&coeff, type); + coeff = kvzalloc(sizeof(*coeff), GFP_KERNEL); + if (!coeff) + goto release; - i = 0; + if (!build_coefficients(coeff, type)) + goto release; - while (i != hw_points_num + 1) { + memset(pow_buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32)); + pow_buffer_ptr = 0; // see variable definition for more info + i = 0; + while (i <= hw_points_num) { /*TODO use y vs r,g,b*/ rgb->r = translate_from_linear_space_ex( - coord_x->x, &coeff, 0); + coord_x->x, coeff, 0); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; ++rgb; ++i; } + pow_buffer_ptr = -1; // reset back to no optimize + ret = true; +release: + kfree(coeff); + return ret; } static void hermite_spline_eetf(struct fixed31_32 input_x, @@ -862,6 +930,8 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, else max_content = max_display; + if (!use_eetf) + pow_buffer_ptr = 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++) { @@ -900,19 +970,23 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, ++coord_x; ++rgb; } + pow_buffer_ptr = -1; return true; } -static void build_degamma(struct pwl_float_data_ex *curve, +static bool build_degamma(struct pwl_float_data_ex *curve, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, enum gamma_type_index type) + const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) { uint32_t i; struct gamma_coefficients coeff; uint32_t begin_index, end_index; + bool ret = false; + + if (!build_coefficients(&coeff, type)) + goto release; - build_coefficients(&coeff, type); i = 0; /* X points is 2^-25 to 2^7 @@ -941,11 +1015,19 @@ static void build_degamma(struct pwl_float_data_ex *curve, curve[i].b = dc_fixpt_one; i++; } + ret = true; +release: + return ret; } + + + + static void build_hlg_degamma(struct pwl_float_data_ex *degamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, bool is_light0_12) + const struct hw_x_point *coordinate_x, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { uint32_t i; @@ -953,9 +1035,9 @@ 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 while (i != hw_points_num + 1) { - compute_hlg_oetf(coord_x->x, is_light0_12, &rgb->r); + compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; @@ -964,9 +1046,11 @@ static void build_hlg_degamma(struct pwl_float_data_ex *degamma, } } + static void build_hlg_regamma(struct pwl_float_data_ex *regamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, bool is_light0_12) + const struct hw_x_point *coordinate_x, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { uint32_t i; @@ -975,8 +1059,9 @@ static void build_hlg_regamma(struct pwl_float_data_ex *regamma, i = 0; + //when i == 471 while (i != hw_points_num + 1) { - compute_hlg_eotf(coord_x->x, is_light0_12, &rgb->r); + compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; @@ -1572,14 +1657,15 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, output_tf->tf == TRANSFER_FUNCTION_SRGB) { if (ramp == NULL) return true; - if ((ramp->is_logical_identity) || + if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) || (!mapUserRamp && ramp->type == GAMMA_RGB_256)) return true; } output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - if (ramp && (mapUserRamp || ramp->type != GAMMA_RGB_256)) { + if (ramp && ramp->type != GAMMA_CS_TFM_1D && + (mapUserRamp || ramp->type != GAMMA_RGB_256)) { rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*rgb_user), GFP_KERNEL); @@ -1634,6 +1720,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, MAX_HW_POINTS, coordinates_x, fs_params); + } else if (tf == TRANSFER_FUNCTION_HLG) { + build_freesync_hdr(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + fs_params); + } else { tf_pts->end_exponent = 0; tf_pts->x_point_at_y1_red = 1; @@ -1642,9 +1734,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, build_regamma(rgb_regamma, MAX_HW_POINTS, - coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? gamma_type_index_2_4 : - tf == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + coordinates_x, tf); } map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, rgb_regamma, @@ -1845,13 +1935,19 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, MAX_HW_POINTS, coordinates_x); else if (tf == TRANSFER_FUNCTION_SRGB || - tf == TRANSFER_FUNCTION_BT709) + tf == TRANSFER_FUNCTION_BT709 || + tf == TRANSFER_FUNCTION_GAMMA22 || + tf == TRANSFER_FUNCTION_GAMMA24 || + tf == TRANSFER_FUNCTION_GAMMA26) build_degamma(curve, MAX_HW_POINTS, coordinates_x, - tf == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : tf == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + tf); + else if (tf == TRANSFER_FUNCTION_HLG) + build_hlg_degamma(curve, + MAX_HW_POINTS, + coordinates_x, + 80, 1000); else if (tf == TRANSFER_FUNCTION_LINEAR) { // just copy coordinates_x into curve i = 0; @@ -1938,7 +2034,10 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_SRGB || - trans == TRANSFER_FUNCTION_BT709) { + trans == TRANSFER_FUNCTION_BT709 || + trans == TRANSFER_FUNCTION_GAMMA22 || + trans == TRANSFER_FUNCTION_GAMMA24 || + trans == TRANSFER_FUNCTION_GAMMA26) { rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_regamma), GFP_KERNEL); @@ -1952,9 +2051,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, build_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : trans == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + trans); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; @@ -1963,18 +2060,21 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, ret = true; kvfree(rgb_regamma); - } else if (trans == TRANSFER_FUNCTION_HLG || - trans == TRANSFER_FUNCTION_HLG12) { + } else if (trans == TRANSFER_FUNCTION_HLG) { rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; + points->end_exponent = 4; + points->x_point_at_y1_red = 12; + points->x_point_at_y1_green = 12; + points->x_point_at_y1_blue = 12; build_hlg_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_HLG12 ? true:false); + 80, 1000); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; @@ -2024,8 +2124,10 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_SRGB || - trans == TRANSFER_FUNCTION_BT709 || - trans == TRANSFER_FUNCTION_GAMMA22) { + trans == TRANSFER_FUNCTION_BT709 || + trans == TRANSFER_FUNCTION_GAMMA22 || + trans == TRANSFER_FUNCTION_GAMMA24 || + trans == TRANSFER_FUNCTION_GAMMA26) { rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_degamma), GFP_KERNEL); @@ -2035,9 +2137,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, build_degamma(rgb_degamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : trans == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + trans); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; @@ -2046,8 +2146,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, ret = true; kvfree(rgb_degamma); - } else if (trans == TRANSFER_FUNCTION_HLG || - trans == TRANSFER_FUNCTION_HLG12) { + } else if (trans == TRANSFER_FUNCTION_HLG) { rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_degamma), GFP_KERNEL); @@ -2057,7 +2156,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, build_hlg_degamma(rgb_degamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_HLG12 ? true:false); + 80, 1000); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; 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 369953fafadf..44ddea58523a 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -82,7 +82,17 @@ struct freesync_hdr_tf_params { unsigned int skip_tm; // skip tm }; +struct translate_from_linear_space_args { + struct fixed31_32 arg; + struct fixed31_32 a0; + struct fixed31_32 a1; + struct fixed31_32 a2; + struct fixed31_32 a3; + struct fixed31_32 gamma; +}; + void setup_x_points_distribution(void); +void log_x_points_distribution(struct dal_logger *logger); void precompute_pq(void); void precompute_de_pq(void); diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 7c20171a3b6d..ec70c9b12e1a 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -52,93 +52,6 @@ struct core_freesync { struct dc *dc; }; -void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value) -{ - unsigned int shift = 0; - - if (!mask || !dest) - return; - - while (!((mask >> shift) & 1)) - shift++; - - //reset - *dest = *dest & ~mask; - //set - //dont let value span past mask - value = value & (mask >> shift); - //insert value - *dest = *dest | (value << shift); -} - -// VTEM Byte Offset -#define VRR_VTEM_PB0 0 -#define VRR_VTEM_PB1 1 -#define VRR_VTEM_PB2 2 -#define VRR_VTEM_PB3 3 -#define VRR_VTEM_PB4 4 -#define VRR_VTEM_PB5 5 -#define VRR_VTEM_PB6 6 - -#define VRR_VTEM_MD0 7 -#define VRR_VTEM_MD1 8 -#define VRR_VTEM_MD2 9 -#define VRR_VTEM_MD3 10 - - -// VTEM Byte Masks -//PB0 -#define MASK__VRR_VTEM_PB0__RESERVED0 0x01 -#define MASK__VRR_VTEM_PB0__SYNC 0x02 -#define MASK__VRR_VTEM_PB0__VFR 0x04 -#define MASK__VRR_VTEM_PB0__AFR 0x08 -#define MASK__VRR_VTEM_PB0__DS_TYPE 0x30 - //0: Periodic pseudo-static EM Data Set - //1: Periodic dynamic EM Data Set - //2: Unique EM Data Set - //3: Reserved -#define MASK__VRR_VTEM_PB0__END 0x40 -#define MASK__VRR_VTEM_PB0__NEW 0x80 - -//PB1 -#define MASK__VRR_VTEM_PB1__RESERVED1 0xFF - -//PB2 -#define MASK__VRR_VTEM_PB2__ORGANIZATION_ID 0xFF - //0: This is a Vendor Specific EM Data Set - //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean) - //2: This EM Data Set is defined by CTA-861-G - //3: This EM Data Set is defined by VESA -//PB3 -#define MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB 0xFF -//PB4 -#define MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB 0xFF -//PB5 -#define MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF -//PB6 -#define MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF - - - -//PB7-27 (20 bytes): -//PB7 = MD0 -#define MASK__VRR_VTEM_MD0__VRR_EN 0x01 -#define MASK__VRR_VTEM_MD0__M_CONST 0x02 -#define MASK__VRR_VTEM_MD0__RESERVED2 0x0C -#define MASK__VRR_VTEM_MD0__FVA_FACTOR_M1 0xF0 - -//MD1 -#define MASK__VRR_VTEM_MD1__BASE_VFRONT 0xFF - -//MD2 -#define MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 -#define MASK__VRR_VTEM_MD2__RB 0x04 -#define MASK__VRR_VTEM_MD2__RESERVED3 0xF8 - -//MD3 -#define MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF - - #define MOD_FREESYNC_TO_CORE(mod_freesync)\ container_of(mod_freesync, struct core_freesync, public) @@ -435,6 +348,12 @@ static void apply_below_the_range(struct core_freesync *core_freesync, /* Either we've calculated the number of frames to insert, * or we need to insert min duration frames */ + if (last_render_time_in_us / frames_to_insert < + in_out_vrr->min_duration_in_us){ + frames_to_insert -= (frames_to_insert > 1) ? + 1 : 0; + } + if (frames_to_insert > 0) inserted_frame_duration_in_us = last_render_time_in_us / frames_to_insert; @@ -568,22 +487,64 @@ bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, return false; } -static void build_vrr_infopacket_header_vtem(enum signal_type signal, +static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, struct dc_info_packet *infopacket) { - // HEADER - - // HB0, HB1, HB2 indicates PacketType VTEMPacket - infopacket->hb0 = 0x7F; - infopacket->hb1 = 0xC0; - infopacket->hb2 = 0x00; //sequence_index - - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB0], MASK__VRR_VTEM_PB0__VFR, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB2], MASK__VRR_VTEM_PB2__ORGANIZATION_ID, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB3], MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB, 0); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB4], MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB5], MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB, 0); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB6], MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB, 4); + /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ + infopacket->sb[1] = 0x1A; + + /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ + infopacket->sb[2] = 0x00; + + /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ + infopacket->sb[3] = 0x00; + + /* PB4 = Reserved */ + + /* PB5 = Reserved */ + + /* PB6 = [Bits 7:3 = Reserved] */ + + /* PB6 = [Bit 0 = FreeSync Supported] */ + if (vrr->state != VRR_STATE_UNSUPPORTED) + infopacket->sb[6] |= 0x01; + + /* PB6 = [Bit 1 = FreeSync Enabled] */ + if (vrr->state != VRR_STATE_DISABLED && + vrr->state != VRR_STATE_UNSUPPORTED) + infopacket->sb[6] |= 0x02; + + /* PB6 = [Bit 2 = FreeSync Active] */ + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || + vrr->state == VRR_STATE_ACTIVE_FIXED) + infopacket->sb[6] |= 0x04; + + /* PB7 = FreeSync Minimum refresh rate (Hz) */ + infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); + + /* PB8 = FreeSync Maximum refresh rate (Hz) + * Note: We should never go above the field rate of the mode timing set. + */ + infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); + + + //FreeSync HDR + infopacket->sb[9] = 0; + infopacket->sb[10] = 0; +} + +static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, + struct dc_info_packet *infopacket) +{ + if (app_tf != TRANSFER_FUNC_UNKNOWN) { + infopacket->valid = true; + + infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] + + if (app_tf == TRANSFER_FUNC_GAMMA_22) { + infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] + } + } } static void build_vrr_infopacket_header_v1(enum signal_type signal, @@ -684,105 +645,6 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal, } } -static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream, - const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - unsigned int fieldRateInHz; - - if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || - vrr->state == VRR_STATE_ACTIVE_FIXED) { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 1); - } else { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 0); - } - - if (!stream->timing.vic) { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD1], MASK__VRR_VTEM_MD1__BASE_VFRONT, - stream->timing.v_front_porch); - - - /* TODO: In dal2, we check mode flags for a reduced blanking timing. - * Need a way to relay that information to this function. - * if("ReducedBlanking") - * { - * setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1; - * } - */ - - //TODO: DAL2 does FixPoint and rounding. Here we might need to account for that - fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/ - (stream->timing.h_total * stream->timing.v_total); - - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98, - fieldRateInHz >> 8); - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD3], MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07, - fieldRateInHz); - - } - infopacket->valid = true; -} - -static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ - infopacket->sb[1] = 0x1A; - - /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ - infopacket->sb[2] = 0x00; - - /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ - infopacket->sb[3] = 0x00; - - /* PB4 = Reserved */ - - /* PB5 = Reserved */ - - /* PB6 = [Bits 7:3 = Reserved] */ - - /* PB6 = [Bit 0 = FreeSync Supported] */ - if (vrr->state != VRR_STATE_UNSUPPORTED) - infopacket->sb[6] |= 0x01; - - /* PB6 = [Bit 1 = FreeSync Enabled] */ - if (vrr->state != VRR_STATE_DISABLED && - vrr->state != VRR_STATE_UNSUPPORTED) - infopacket->sb[6] |= 0x02; - - /* PB6 = [Bit 2 = FreeSync Active] */ - if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || - vrr->state == VRR_STATE_ACTIVE_FIXED) - infopacket->sb[6] |= 0x04; - - /* PB7 = FreeSync Minimum refresh rate (Hz) */ - infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); - - /* PB8 = FreeSync Maximum refresh rate (Hz) - * Note: We should never go above the field rate of the mode timing set. - */ - infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); - - - //FreeSync HDR - infopacket->sb[9] = 0; - infopacket->sb[10] = 0; -} - -static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, - struct dc_info_packet *infopacket) -{ - if (app_tf != TRANSFER_FUNC_UNKNOWN) { - infopacket->valid = true; - - infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] - - if (app_tf == TRANSFER_FUNC_GAMMA_22) { - infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] - } - } -} - static void build_vrr_infopacket_checksum(unsigned int *payload_size, struct dc_info_packet *infopacket) { @@ -835,21 +697,6 @@ static void build_vrr_infopacket_v2(enum signal_type signal, infopacket->valid = true; } -static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream, - const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - //VTEM info packet for HdmiVrr - - memset(infopacket, 0, sizeof(struct dc_info_packet)); - - //VTEM Packet is structured differently - build_vrr_infopacket_header_vtem(stream->signal, infopacket); - build_vrr_vtem_infopacket_data(stream, vrr, infopacket); - - infopacket->valid = true; -} - void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, const struct dc_stream_state *stream, const struct mod_vrr_params *vrr, @@ -862,16 +709,13 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, * Check if Freesync is supported. Return if false. If true, * set the corresponding bit in the info packet */ - if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM)) + if (!vrr->supported || (!vrr->send_info_frame)) return; switch (packet_type) { case PACKET_TYPE_FS2: build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); break; - case PACKET_TYPE_VTEM: - build_vrr_infopacket_vtem(stream, vrr, infopacket); - break; case PACKET_TYPE_VRR: case PACKET_TYPE_FS1: default: @@ -887,8 +731,8 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, struct core_freesync *core_freesync = NULL; unsigned long long nominal_field_rate_in_uhz = 0; unsigned int refresh_range = 0; - unsigned int min_refresh_in_uhz = 0; - unsigned int max_refresh_in_uhz = 0; + unsigned long long min_refresh_in_uhz = 0; + unsigned long long max_refresh_in_uhz = 0; if (mod_freesync == NULL) return; @@ -915,7 +759,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, min_refresh_in_uhz = nominal_field_rate_in_uhz; if (!vrr_settings_require_update(core_freesync, - in_config, min_refresh_in_uhz, max_refresh_in_uhz, + in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz, in_out_vrr)) return; @@ -931,15 +775,15 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, return; } else { - in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz; + in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz; in_out_vrr->max_duration_in_us = calc_duration_in_us_from_refresh_in_uhz( - min_refresh_in_uhz); + (unsigned int)min_refresh_in_uhz); - in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz; + in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz; in_out_vrr->min_duration_in_us = calc_duration_in_us_from_refresh_in_uhz( - max_refresh_in_uhz); + (unsigned int)max_refresh_in_uhz); refresh_range = in_out_vrr->max_refresh_in_uhz - in_out_vrr->min_refresh_in_uhz; @@ -950,17 +794,18 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, in_out_vrr->fixed.ramping_active = in_config->ramping; in_out_vrr->btr.btr_enabled = in_config->btr; + if (in_out_vrr->max_refresh_in_uhz < 2 * in_out_vrr->min_refresh_in_uhz) in_out_vrr->btr.btr_enabled = false; + in_out_vrr->btr.btr_active = false; in_out_vrr->btr.inserted_duration_in_us = 0; in_out_vrr->btr.frames_to_insert = 0; in_out_vrr->btr.frame_counter = 0; in_out_vrr->btr.mid_point_in_us = - in_out_vrr->min_duration_in_us + - (in_out_vrr->max_duration_in_us - - in_out_vrr->min_duration_in_us) / 2; + (in_out_vrr->min_duration_in_us + + in_out_vrr->max_duration_in_us) / 2; if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { in_out_vrr->adjust.v_total_min = stream->timing.v_total; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index dcef85994c45..dc187844d10b 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -173,4 +173,6 @@ bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, uint32_t min_refresh_request_in_uhz, uint32_t max_refresh_request_in_uhz); + + #endif diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h index 5b1c9a4c7643..d930bdecb117 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h @@ -27,10 +27,10 @@ #define MOD_INFO_PACKET_H_ #include "mod_shared.h" - //Forward Declarations struct dc_stream_state; struct dc_info_packet; +struct mod_vrr_params; void mod_build_vsc_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet); diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index bc13c552797f..d885d642ed7f 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -27,9 +27,78 @@ #include "core_types.h" #include "dc_types.h" #include "mod_shared.h" +#include "mod_freesync.h" +#include "dc.h" #define HDMI_INFOFRAME_TYPE_VENDOR 0x81 +// VTEM Byte Offset +#define VTEM_PB0 0 +#define VTEM_PB1 1 +#define VTEM_PB2 2 +#define VTEM_PB3 3 +#define VTEM_PB4 4 +#define VTEM_PB5 5 +#define VTEM_PB6 6 + +#define VTEM_MD0 7 +#define VTEM_MD1 8 +#define VTEM_MD2 9 +#define VTEM_MD3 10 + + +// VTEM Byte Masks +//PB0 +#define MASK_VTEM_PB0__RESERVED0 0x01 +#define MASK_VTEM_PB0__SYNC 0x02 +#define MASK_VTEM_PB0__VFR 0x04 +#define MASK_VTEM_PB0__AFR 0x08 +#define MASK_VTEM_PB0__DS_TYPE 0x30 + //0: Periodic pseudo-static EM Data Set + //1: Periodic dynamic EM Data Set + //2: Unique EM Data Set + //3: Reserved +#define MASK_VTEM_PB0__END 0x40 +#define MASK_VTEM_PB0__NEW 0x80 + +//PB1 +#define MASK_VTEM_PB1__RESERVED1 0xFF + +//PB2 +#define MASK_VTEM_PB2__ORGANIZATION_ID 0xFF + //0: This is a Vendor Specific EM Data Set + //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean) + //2: This EM Data Set is defined by CTA-861-G + //3: This EM Data Set is defined by VESA +//PB3 +#define MASK_VTEM_PB3__DATA_SET_TAG_MSB 0xFF +//PB4 +#define MASK_VTEM_PB4__DATA_SET_TAG_LSB 0xFF +//PB5 +#define MASK_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF +//PB6 +#define MASK_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF + + + +//PB7-27 (20 bytes): +//PB7 = MD0 +#define MASK_VTEM_MD0__VRR_EN 0x01 +#define MASK_VTEM_MD0__M_CONST 0x02 +#define MASK_VTEM_MD0__RESERVED2 0x0C +#define MASK_VTEM_MD0__FVA_FACTOR_M1 0xF0 + +//MD1 +#define MASK_VTEM_MD1__BASE_VFRONT 0xFF + +//MD2 +#define MASK_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 +#define MASK_VTEM_MD2__RB 0x04 +#define MASK_VTEM_MD2__RESERVED3 0xF8 + +//MD3 +#define MASK_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF + enum ColorimetryRGBDP { ColorimetryRGB_DP_sRGB = 0, ColorimetryRGB_DP_AdobeRGB = 3, 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 b3810b864676..05e2be856037 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -66,6 +66,39 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le { 3, 6, 10, 12 }, /* Alt #3 - Super aggressiveness */ }; +struct abm_parameters { + unsigned char min_reduction; + unsigned char max_reduction; + unsigned char bright_pos_gain; + unsigned char dark_pos_gain; + unsigned char brightness_gain; + unsigned char contrast_factor; + unsigned char deviation_gain; + unsigned char min_knee; + unsigned char max_knee; +}; + +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}, + {0xff, 0x85, 0x20, 0x00, 0xff, 0x90, 0xa8, 0x40, 0xE0}, + {0xff, 0x40, 0x20, 0x00, 0xff, 0x90, 0x68, 0x40, 0xE0}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0x90, 0xb3, 0x70, 0x70}, +}; + +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, 0xa8, 0xb3, 0x70, 0x70}, + {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, + {0x99, 0x65, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, +}; + +static const struct abm_parameters * const abm_settings[] = { + abm_settings_config0, + abm_settings_config1, +}; + #define NUM_AMBI_LEVEL 5 #define NUM_AGGR_LEVEL 4 #define NUM_POWER_FN_SEGS 8 @@ -131,11 +164,13 @@ struct iram_table_v_2_2 { uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */ uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */ uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */ - uint8_t hybridFactor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */ - uint8_t contrastFactor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */ + uint8_t hybrid_factor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */ + uint8_t contrast_factor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */ uint8_t deviation_gain[NUM_AGGR_LEVEL]; /* 0x5a U0.8 */ uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x5e U0.8 */ - uint8_t pad[29]; /* 0x63 U0.8 */ + uint8_t min_knee[NUM_AGGR_LEVEL]; /* 0x63 U0.8 */ + uint8_t max_knee[NUM_AGGR_LEVEL]; /* 0x67 U0.8 */ + uint8_t pad[21]; /* 0x6b U0.8 */ /* parameters for crgb conversion */ uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */ @@ -501,15 +536,72 @@ void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parame ram_table->dark_pos_gain[4][2] = 0x00; ram_table->dark_pos_gain[4][3] = 0x00; - ram_table->hybridFactor[0] = 0xff; - ram_table->hybridFactor[1] = 0xff; - ram_table->hybridFactor[2] = 0xff; - ram_table->hybridFactor[3] = 0xc0; + ram_table->hybrid_factor[0] = 0xff; + ram_table->hybrid_factor[1] = 0xff; + ram_table->hybrid_factor[2] = 0xff; + ram_table->hybrid_factor[3] = 0xc0; - ram_table->contrastFactor[0] = 0x99; - ram_table->contrastFactor[1] = 0x99; - ram_table->contrastFactor[2] = 0x90; - ram_table->contrastFactor[3] = 0x80; + ram_table->contrast_factor[0] = 0x99; + ram_table->contrast_factor[1] = 0x99; + ram_table->contrast_factor[2] = 0x90; + ram_table->contrast_factor[3] = 0x80; + + ram_table->iir_curve[0] = 0x65; + ram_table->iir_curve[1] = 0x65; + ram_table->iir_curve[2] = 0x65; + ram_table->iir_curve[3] = 0x65; + ram_table->iir_curve[4] = 0x65; + + //Gamma 2.2 + ram_table->crgb_thresh[0] = cpu_to_be16(0x127c); + ram_table->crgb_thresh[1] = cpu_to_be16(0x151b); + ram_table->crgb_thresh[2] = cpu_to_be16(0x17d5); + ram_table->crgb_thresh[3] = cpu_to_be16(0x1a56); + ram_table->crgb_thresh[4] = cpu_to_be16(0x1c83); + ram_table->crgb_thresh[5] = cpu_to_be16(0x1e72); + ram_table->crgb_thresh[6] = cpu_to_be16(0x20f0); + ram_table->crgb_thresh[7] = cpu_to_be16(0x232b); + ram_table->crgb_offset[0] = cpu_to_be16(0x2999); + ram_table->crgb_offset[1] = cpu_to_be16(0x3999); + ram_table->crgb_offset[2] = cpu_to_be16(0x4666); + ram_table->crgb_offset[3] = cpu_to_be16(0x5999); + ram_table->crgb_offset[4] = cpu_to_be16(0x6333); + ram_table->crgb_offset[5] = cpu_to_be16(0x7800); + ram_table->crgb_offset[6] = cpu_to_be16(0x8c00); + ram_table->crgb_offset[7] = cpu_to_be16(0xa000); + ram_table->crgb_slope[0] = cpu_to_be16(0x3609); + ram_table->crgb_slope[1] = cpu_to_be16(0x2dfa); + ram_table->crgb_slope[2] = cpu_to_be16(0x27ea); + ram_table->crgb_slope[3] = cpu_to_be16(0x235d); + ram_table->crgb_slope[4] = cpu_to_be16(0x2042); + ram_table->crgb_slope[5] = cpu_to_be16(0x1dc3); + ram_table->crgb_slope[6] = cpu_to_be16(0x1b1a); + ram_table->crgb_slope[7] = cpu_to_be16(0x1910); + + fill_backlight_transform_table_v_2_2( + params, ram_table); +} + +void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params) +{ + unsigned int i, j; + unsigned int set = params.set; + + ram_table->flags = 0x0; + for (i = 0; i < NUM_AGGR_LEVEL; i++) { + ram_table->hybrid_factor[i] = abm_settings[set][i].brightness_gain; + ram_table->contrast_factor[i] = abm_settings[set][i].contrast_factor; + ram_table->deviation_gain[i] = abm_settings[set][i].deviation_gain; + ram_table->min_knee[i] = abm_settings[set][i].min_knee; + ram_table->max_knee[i] = abm_settings[set][i].max_knee; + + for (j = 0; j < NUM_AMBI_LEVEL; j++) { + ram_table->min_reduction[j][i] = abm_settings[set][i].min_reduction; + ram_table->max_reduction[j][i] = abm_settings[set][i].max_reduction; + ram_table->bright_pos_gain[j][i] = abm_settings[set][i].bright_pos_gain; + ram_table->dark_pos_gain[j][i] = abm_settings[set][i].dark_pos_gain; + } + } ram_table->iir_curve[0] = 0x65; ram_table->iir_curve[1] = 0x65; @@ -561,7 +653,12 @@ bool dmcu_load_iram(struct dmcu *dmcu, memset(&ram_table, 0, sizeof(ram_table)); - if (dmcu->dmcu_version.abm_version == 0x22) { + if (dmcu->dmcu_version.abm_version == 0x23) { + fill_iram_v_2_3((struct iram_table_v_2_2 *)ram_table, params); + + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2); + } else if (dmcu->dmcu_version.abm_version == 0x22) { fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params); result = dmcu->funcs->load_iram( |