@@ -1303,6 +1303,20 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev)
return -ENOMEM;
adev->mode_info.gamma_tf_property = prop;
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+ "AMD_PLANE_DEGAMMA_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_degamma_lut_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+ DRM_MODE_PROP_IMMUTABLE,
+ "AMD_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_degamma_lut_size_property = prop;
+
return 0;
}
#endif
@@ -372,6 +372,16 @@ struct amdgpu_mode_info {
* @gamma_tf_property: Transfer function for CRTC regamma.
*/
struct drm_property *gamma_tf_property;
+ /**
+ * @plane_degamma_lut_property: Plane property to set a degamma LUT to
+ * convert color space before blending.
+ */
+ struct drm_property *plane_degamma_lut_property;
+ /**
+ * @plane_degamma_lut_size_property: Plane property to define the max
+ * size of degamma LUT as supported by the driver (read-only).
+ */
+ struct drm_property *plane_degamma_lut_size_property;
#endif
};
@@ -719,6 +719,17 @@ enum drm_transfer_function {
struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
+
+#ifdef CONFIG_STEAM_DECK
+ /* Plane color mgmt */
+ /**
+ * @degamma_lut:
+ *
+ * LUT for converting plane pixel data before going into plane merger.
+ * The blob (if not NULL) is an array of &struct drm_color_lut.
+ */
+ struct drm_property_blob *degamma_lut;
+#endif
};
struct dm_crtc_state {
@@ -1337,7 +1337,10 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
dm_plane_state->dc_state = old_dm_plane_state->dc_state;
dc_plane_state_retain(dm_plane_state->dc_state);
}
-
+#ifdef CONFIG_STEAM_DECK
+ if (dm_plane_state->degamma_lut)
+ drm_property_blob_get(dm_plane_state->degamma_lut);
+#endif
return &dm_plane_state->base;
}
@@ -1404,7 +1407,9 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
-
+#ifdef CONFIG_STEAM_DECK
+ drm_property_blob_put(dm_plane_state->degamma_lut);
+#endif
if (dm_plane_state->dc_state)
dc_plane_state_release(dm_plane_state->dc_state);
@@ -1444,6 +1449,68 @@ amdgpu_dm_replace_property_blob_from_id(struct drm_device *dev,
return 0;
}
+
+static void
+dm_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm,
+ struct drm_plane *plane)
+{
+ if (dm->dc->caps.color.dpp.dgam_ram || dm->dc->caps.color.dpp.gamma_corr ) {
+ drm_object_attach_property(&plane->base,
+ dm->adev->mode_info.plane_degamma_lut_property, 0);
+ drm_object_attach_property(&plane->base,
+ dm->adev->mode_info.plane_degamma_lut_size_property,
+ MAX_COLOR_LUT_ENTRIES);
+ }
+}
+
+static int
+dm_atomic_plane_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property, uint64_t val)
+{
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
+ bool replaced = false;
+ int ret;
+
+ if (property == adev->mode_info.plane_degamma_lut_property) {
+ ret = amdgpu_dm_replace_property_blob_from_id(plane->dev,
+ &dm_plane_state->degamma_lut,
+ val,
+ -1, sizeof(struct drm_color_lut),
+ &replaced);
+ dm_plane_state->base.color_mgmt_changed |= replaced;
+ return ret;
+ } else {
+ drm_dbg_atomic(plane->dev,
+ "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
+ plane->base.id, plane->name,
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+dm_atomic_plane_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+
+{
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
+
+ if (property == adev->mode_info.plane_degamma_lut_property) {
+ *val = (dm_plane_state->degamma_lut) ?
+ dm_plane_state->degamma_lut->base.id : 0;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
#endif
static const struct drm_plane_funcs dm_plane_funcs = {
@@ -1454,6 +1521,10 @@ static const struct drm_plane_funcs dm_plane_funcs = {
.atomic_duplicate_state = dm_drm_plane_duplicate_state,
.atomic_destroy_state = dm_drm_plane_destroy_state,
.format_mod_supported = dm_plane_format_mod_supported,
+#ifdef CONFIG_STEAM_DECK
+ .atomic_set_property = dm_atomic_plane_set_property,
+ .atomic_get_property = dm_atomic_plane_get_property,
+#endif
};
int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
@@ -1524,6 +1595,9 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
drm_plane_helper_add(plane, &dm_plane_helper_funcs);
+#ifdef CONFIG_STEAM_DECK
+ dm_plane_attach_color_mgmt_properties(dm, plane);
+#endif
/* Create (reset) the plane state */
if (plane->funcs->reset)
plane->funcs->reset(plane);