drm/amd/display: Implement custom degamma lut on dcn
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm_color.c
index b329393..326f6fb 100644 (file)
@@ -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;
 }