From: "Leo (Sunpeng) Li" <sunpeng.li@xxxxxxx> Points in the DRM LUT are spaced linearly. Points in hardware are spaced exponentially, with greater density towards 0. To maintain low-end accuracy in hardware when sampling the DRM LUT, more points are needed. However, X doesn't seem to play with legacy LUTs of such size. Therefore, check for legacy lut when updating DC states, and update accordingly. v2: Use a macro for the maximum drm LUT value. v3: Update commit to reflect that this does not map 1-1 to HW Signed-off-by: Leo (Sunpeng) Li <sunpeng.li at amd.com> Reviewed-by: Harry Wentland <Harry.Wentland at amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 4 +- .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 77 ++++++++++++++++------ 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index bb9405daa087..f782518fc424 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3228,7 +3228,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, dm->adev->mode_info.crtcs[crtc_index] = acrtc; drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES, true, MAX_COLOR_LUT_ENTRIES); - drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LUT_ENTRIES); + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 5b5fa80916cb..b4c48c5edc47 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -269,7 +269,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); #define amdgpu_dm_crtc_handle_crc_irq(x) #endif -#define MAX_COLOR_LUT_ENTRIES 256 +#define MAX_COLOR_LUT_ENTRIES 4096 +/* Legacy gamm LUT users such as X doesn't like large LUT sizes */ +#define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, 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 62bb72fe9aa5..e845c511656e 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 @@ -27,6 +27,8 @@ #include "amdgpu_dm.h" #include "modules/color/color_gamma.h" +#define MAX_DRM_LUT_VALUE 0xFFFF + /* * Initialize the color module. * @@ -47,19 +49,18 @@ void amdgpu_dm_init_color_mod(void) * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in * [0, MAX_COLOR_LUT_ENTRIES) */ -static bool __is_lut_linear(struct drm_color_lut *lut) +static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size) { int i; - uint32_t max_os = 0xFF00; uint32_t expected; int delta; - for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) { + for (i = 0; i < size; i++) { /* All color values should equal */ if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue)) return false; - expected = i * max_os / (MAX_COLOR_LUT_ENTRIES-1); + expected = i * MAX_DRM_LUT_VALUE / (size-1); /* Allow a +/-1 error. */ delta = lut[i].red - expected; @@ -69,6 +70,42 @@ static bool __is_lut_linear(struct drm_color_lut *lut) return true; } +/** + * Convert the drm_color_lut to dc_gamma. The conversion depends on the size + * of the lut - whether or not it's legacy. + */ +static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut, + struct dc_gamma *gamma, + bool is_legacy) +{ + uint32_t r, g, b; + int i; + + if (is_legacy) { + for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) { + r = drm_color_lut_extract(lut[i].red, 16); + g = drm_color_lut_extract(lut[i].green, 16); + b = drm_color_lut_extract(lut[i].blue, 16); + + gamma->entries.red[i] = dal_fixed31_32_from_int(r); + gamma->entries.green[i] = dal_fixed31_32_from_int(g); + gamma->entries.blue[i] = dal_fixed31_32_from_int(b); + } + return; + } + + /* else */ + for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) { + r = drm_color_lut_extract(lut[i].red, 16); + g = drm_color_lut_extract(lut[i].green, 16); + b = drm_color_lut_extract(lut[i].blue, 16); + + gamma->entries.red[i] = dal_fixed31_32_from_fraction(r, MAX_DRM_LUT_VALUE); + gamma->entries.green[i] = dal_fixed31_32_from_fraction(g, MAX_DRM_LUT_VALUE); + gamma->entries.blue[i] = dal_fixed31_32_from_fraction(b, MAX_DRM_LUT_VALUE); + } +} + /** * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC. * @crtc: amdgpu_dm crtc state @@ -85,11 +122,10 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) struct drm_property_blob *blob = crtc->base.gamma_lut; struct dc_stream_state *stream = crtc->stream; struct drm_color_lut *lut; + uint32_t lut_size; struct dc_gamma *gamma; enum dc_transfer_func_type old_type = stream->out_transfer_func->type; - uint32_t r, g, b; - int i; bool ret; if (!blob) { @@ -100,8 +136,9 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) } lut = (struct drm_color_lut *)blob->data; + lut_size = blob->length / sizeof(struct drm_color_lut); - if (__is_lut_linear(lut)) { + if (__is_lut_linear(lut, lut_size)) { /* Set to bypass if lut is set to linear */ stream->out_transfer_func->type = TF_TYPE_BYPASS; stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; @@ -112,20 +149,20 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) if (!gamma) return -ENOMEM; - gamma->num_entries = MAX_COLOR_LUT_ENTRIES; - gamma->type = GAMMA_RGB_256; - - /* Truncate, and store in dc_gamma for output tf calculation */ - for (i = 0; i < gamma->num_entries; i++) { - r = drm_color_lut_extract(lut[i].red, 16); - g = drm_color_lut_extract(lut[i].green, 16); - b = drm_color_lut_extract(lut[i].blue, 16); - - gamma->entries.red[i] = dal_fixed31_32_from_int(r); - gamma->entries.green[i] = dal_fixed31_32_from_int(g); - gamma->entries.blue[i] = dal_fixed31_32_from_int(b); + gamma->num_entries = lut_size; + if (gamma->num_entries == MAX_COLOR_LEGACY_LUT_ENTRIES) + gamma->type = GAMMA_RGB_256; + else if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) + gamma->type = GAMMA_CS_TFM_1D; + else { + /* Invalid lut size */ + dc_gamma_release(&gamma); + return -EINVAL; } + /* Convert drm_lut into dc_gamma */ + __drm_lut_to_dc_gamma(lut, gamma, gamma->type == GAMMA_RGB_256); + /* Call color module to translate into something DC understands. Namely * a transfer function. */ @@ -212,7 +249,7 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, } lut = (struct drm_color_lut *)blob->data; - if (__is_lut_linear(lut)) { + if (__is_lut_linear(lut, MAX_COLOR_LUT_ENTRIES)) { dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; return 0; -- 2.14.1