diff options
author | David Francis <David.Francis@amd.com> | 2018-07-12 15:46:41 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2018-08-06 14:35:25 -0500 |
commit | 78e4405cec6cb0780b27b222685dde33934b38e4 (patch) | |
tree | 6fa8772651eff98d82abad618374a3117bc4a948 /drivers/gpu | |
parent | d90e9a3bf5e747f0e3b0c8bec96d8699493f63ab (diff) | |
download | linux-stable-78e4405cec6cb0780b27b222685dde33934b38e4.tar.gz linux-stable-78e4405cec6cb0780b27b222685dde33934b38e4.tar.bz2 linux-stable-78e4405cec6cb0780b27b222685dde33934b38e4.zip |
drm/amd/display: Implement custom degamma lut on dcn
[Why]
Custom degamma lut functions are a feature we would
like to support on compatible hardware
[How]
In atomic check, convert from array of drm_color_lut to
dc_transfer_func. On hardware commit, allow for possibility
of custom degamma. Both are based on the equivalent
regamma pipeline.
Signed-off-by: David Francis <David.Francis@amd.com>
Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com>
Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
4 files changed, 46 insertions, 15 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index b329393307e5..326f6fb7e0bc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -231,18 +231,21 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) * preparation for hardware commit. If no lut is specified by user, we default * to SRGB degamma. * - * Currently, we only support degamma bypass, or preprogrammed SRGB degamma. - * Programmable degamma is not supported, and an attempt to do so will return - * -EINVAL. + * We support degamma bypass, predefined SRGB, and custom degamma * * RETURNS: - * 0 on success, -EINVAL if custom degamma curve is given. + * 0 on success + * -EINVAL if crtc_state has a degamma_lut of invalid size + * -ENOMEM if gamma allocation fails */ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, struct dc_plane_state *dc_plane_state) { struct drm_property_blob *blob = crtc_state->degamma_lut; struct drm_color_lut *lut; + uint32_t lut_size; + struct dc_gamma *gamma; + bool ret; if (!blob) { /* Default to SRGB */ @@ -258,11 +261,30 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, return 0; } - /* Otherwise, assume SRGB, since programmable degamma is not - * supported. - */ - dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; - dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - return -EINVAL; + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + lut_size = blob->length / sizeof(struct drm_color_lut); + gamma->num_entries = lut_size; + if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) + gamma->type = GAMMA_CUSTOM; + else { + dc_gamma_release(&gamma); + return -EINVAL; + } + + __drm_lut_to_dc_gamma(lut, gamma, false); + + dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + ret = mod_color_calculate_degamma_params(dc_plane_state->in_transfer_func, gamma, true); + dc_gamma_release(&gamma); + if (!ret) { + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + DRM_ERROR("Out of memory when calculating degamma params\n"); + return -ENOMEM; + } + + return 0; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 1d1f2d5ece51..b789cb2b354b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -417,6 +417,7 @@ enum { GAMMA_RGB_256_ENTRIES = 256, GAMMA_RGB_FLOAT_1024_ENTRIES = 1024, GAMMA_CS_TFM_1D_ENTRIES = 4096, + GAMMA_CUSTOM_ENTRIES = 4096, GAMMA_MAX_ENTRIES = 4096 }; @@ -424,6 +425,7 @@ enum dc_gamma_type { GAMMA_RGB_256 = 1, GAMMA_RGB_FLOAT_1024 = 2, GAMMA_CS_TFM_1D = 3, + GAMMA_CUSTOM = 4, }; struct dc_csc_transform { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index c87f6e603055..f5d8242eb047 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1213,8 +1213,11 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, } else if (tf->type == TF_TYPE_BYPASS) { dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); } else { - /*TF_TYPE_DISTRIBUTED_POINTS*/ - result = false; + cm_helper_translate_curve_to_degamma_hw_format(tf, + &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &dpp_base->degamma_params); + result = true; } return result; 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 ee69c949bfbf..bf29733958c3 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -997,7 +997,9 @@ static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb, * norm_y = 4095*regamma_y, and index is just truncating to nearest integer * lut1 = lut1D[index], lut2 = lut1D[index+1] * - *adjustedY is then linearly interpolating regamma Y between lut1 and lut2 + * adjustedY is then linearly interpolating regamma Y between lut1 and lut2 + * + * Custom degamma on Linux uses the same interpolation math, so is handled here */ static void apply_lut_1d( const struct dc_gamma *ramp, @@ -1018,7 +1020,7 @@ static void apply_lut_1d( struct fixed31_32 delta_lut; struct fixed31_32 delta_index; - if (ramp->type != GAMMA_CS_TFM_1D) + if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM) return; // this is not expected for (i = 0; i < num_hw_points; i++) { @@ -1636,7 +1638,9 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axix_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp); + mapUserRamp && ramp->type != GAMMA_CUSTOM); + if (ramp->type == GAMMA_CUSTOM) + apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); ret = true; |