@@ -929,6 +929,54 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_atomic_helper_check_planes);
+/**
+ * drm_atomic_helper_check_crtcs - validate state object for CRTC changes
+ * @state: the driver state object
+ *
+ * Check the CRTC state object such as the Gamma/Degamma LUT sizes if the new
+ * state holds them.
+ *
+ * RETURNS:
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_check_crtcs(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_crtc_state;
+ int i;
+
+ for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
+ if (!new_crtc_state->color_mgmt_changed)
+ continue;
+
+ if (drm_check_lut_size(new_crtc_state->gamma_lut,
+ crtc->gamma_lut_size) ||
+ drm_check_lut_size(new_crtc_state->gamma_lut,
+ crtc->gamma_size)) {
+ drm_dbg_state(
+ state->dev,
+ "Invalid Gamma LUT size. Expected %u/%u, got %u.\n",
+ crtc->gamma_lut_size, crtc->gamma_size,
+ drm_color_lut_size(new_crtc_state->gamma_lut));
+ return -EINVAL;
+ }
+
+ if (drm_check_lut_size(new_crtc_state->degamma_lut,
+ crtc->degamma_lut_size)) {
+ drm_dbg_state(
+ state->dev,
+ "Invalid Degamma LUT size. Expected %u, got %u.\n",
+ crtc->degamma_lut_size,
+ drm_color_lut_size(
+ new_crtc_state->degamma_lut));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_check_crtcs);
+
/**
* drm_atomic_helper_check - validate state object
* @dev: DRM device
@@ -974,6 +1022,10 @@ int drm_atomic_helper_check(struct drm_device *dev,
if (ret)
return ret;
+ ret = drm_atomic_helper_check_crtcs(state);
+ if (ret)
+ return ret;
+
if (state->legacy_cursor_update)
state->async_update = !drm_atomic_helper_async_check(dev, state);
@@ -166,6 +166,7 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
struct drm_mode_config *config = &dev->mode_config;
if (degamma_lut_size) {
+ crtc->degamma_lut_size = degamma_lut_size;
drm_object_attach_property(&crtc->base,
config->degamma_lut_property, 0);
drm_object_attach_property(&crtc->base,
@@ -178,6 +179,7 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
config->ctm_property, 0);
if (gamma_lut_size) {
+ crtc->gamma_lut_size = gamma_lut_size;
drm_object_attach_property(&crtc->base,
config->gamma_lut_property, 0);
drm_object_attach_property(&crtc->base,
@@ -506,6 +508,23 @@ const char *drm_get_color_range_name(enum drm_color_range range)
return color_range_name[range];
}
+/**
+ * drm_check_lut_size - Checks if LUT size matches the driver expected size.
+ * @lut: blob containing the LUT
+ * @expected_size: driver expected LUT size
+ *
+ * Returns -EINVAL on mismatch, 0 on match.
+ */
+int drm_check_lut_size(const struct drm_property_blob *lut,
+ uint32_t expected_size)
+{
+ if (!lut)
+ return 0;
+
+ return drm_color_lut_size(lut) != expected_size ? -EINVAL : 0;
+}
+EXPORT_SYMBOL(drm_check_lut_size);
+
/**
* drm_plane_create_color_properties - color encoding related plane properties
* @plane: plane object
@@ -1262,23 +1262,6 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state)
return 0;
}
-static int check_lut_size(const struct drm_property_blob *lut, int expected)
-{
- int len;
-
- if (!lut)
- return 0;
-
- len = drm_color_lut_size(lut);
- if (len != expected) {
- DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n",
- len, expected);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int test_luts(const struct drm_property_blob *lut, u32 tests)
{
const struct drm_color_lut *entry;
@@ -1336,9 +1319,20 @@ static int check_luts(const struct intel_crtc_state *crtc_state)
degamma_channels_tests = INTEL_INFO(dev_priv)->color.degamma_lut_tests;
gamma_channels_tests = INTEL_INFO(dev_priv)->color.gamma_lut_tests;
- if (check_lut_size(degamma_lut, degamma_length) ||
- check_lut_size(gamma_lut, gamma_length))
+ if (drm_check_lut_size(degamma_lut, degamma_length)) {
+ drm_dbg_state(
+ &dev_priv->drm,
+ "Invalid Degamma LUT size. Expected %u, got %u.\n",
+ degamma_length, drm_color_lut_size(degamma_lut));
return -EINVAL;
+ }
+
+ if (drm_check_lut_size(gamma_lut, gamma_length)) {
+ drm_dbg_state(&dev_priv->drm,
+ "Invalid Gamma LUT size. Expected %u, got %u.\n",
+ degamma_length, drm_color_lut_size(gamma_lut));
+ return -EINVAL;
+ }
if (test_luts(degamma_lut, degamma_channels_tests) ||
test_luts(gamma_lut, gamma_channels_tests))
@@ -38,6 +38,7 @@ struct drm_atomic_state;
struct drm_private_obj;
struct drm_private_state;
+int drm_atomic_helper_check_crtcs(struct drm_atomic_state *state);
int drm_atomic_helper_check_modeset(struct drm_device *dev,
struct drm_atomic_state *state);
int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
@@ -74,6 +74,9 @@ static inline int drm_color_lut_size(const struct drm_property_blob *blob)
return blob->length / sizeof(struct drm_color_lut);
}
+int drm_check_lut_size(const struct drm_property_blob *lut,
+ uint32_t expected_size);
+
enum drm_color_encoding {
DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_BT709,
@@ -1072,6 +1072,17 @@ struct drm_crtc {
/** @funcs: CRTC control functions */
const struct drm_crtc_funcs *funcs;
+ /**
+ * @degamma_lut_size: Size of degamma LUT.
+ */
+ size_t degamma_lut_size;
+
+ /**
+ * @gamma_lut_size: Size of Gamma LUT. Not used by legacy userspace such as
+ * X, which doesn't support large lut sizes.
+ */
+ size_t gamma_lut_size;
+
/**
* @gamma_size: Size of legacy gamma ramp reported to userspace. Set up
* by calling drm_mode_crtc_set_gamma_size().