diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 33 |
4 files changed, 263 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 8fb469c4e4b8..c7e7a955bb1e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@ #include <drm/drmP.h> #include <drm/drm_atomic.h> +#include <drm/drm_mode.h> #include <drm/drm_plane_helper.h> /** @@ -388,6 +389,59 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); /** + * drm_atomic_replace_property_blob - replace a blob property + * @blob: a pointer to the member blob to be replaced + * @new_blob: the new blob to replace with + * @expected_size: the expected size of the new blob + * @replaced: whether the blob has been replaced + * + * RETURNS: + * Zero on success, error code on failure + */ +static void +drm_atomic_replace_property_blob(struct drm_property_blob **blob, + struct drm_property_blob *new_blob, + bool *replaced) +{ + struct drm_property_blob *old_blob = *blob; + + if (old_blob == new_blob) + return; + + if (old_blob) + drm_property_unreference_blob(old_blob); + if (new_blob) + drm_property_reference_blob(new_blob); + *blob = new_blob; + *replaced = true; + + return; +} + +static int +drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, + struct drm_property_blob **blob, + uint64_t blob_id, + ssize_t expected_size, + bool *replaced) +{ + struct drm_device *dev = crtc->dev; + struct drm_property_blob *new_blob = NULL; + + if (blob_id != 0) { + new_blob = drm_property_lookup_blob(dev, blob_id); + if (new_blob == NULL) + return -EINVAL; + if (expected_size > 0 && expected_size != new_blob->length) + return -EINVAL; + } + + drm_atomic_replace_property_blob(blob, new_blob, replaced); + + return 0; +} + +/** * drm_atomic_crtc_set_property - set property on CRTC * @crtc: the drm CRTC to set a property on * @state: the state object to update with the new property value @@ -409,6 +463,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_mode_config *config = &dev->mode_config; + bool replaced = false; int ret; if (property == config->prop_active) @@ -419,8 +474,31 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ret = drm_atomic_set_mode_prop_for_crtc(state, mode); drm_property_unreference_blob(mode); return ret; - } - else if (crtc->funcs->atomic_set_property) + } else if (property == config->degamma_lut_property) { + ret = drm_atomic_replace_property_blob_from_id(crtc, + &state->degamma_lut, + val, + -1, + &replaced); + state->color_mgmt_changed = replaced; + return ret; + } else if (property == config->ctm_property) { + ret = drm_atomic_replace_property_blob_from_id(crtc, + &state->ctm, + val, + sizeof(struct drm_color_ctm), + &replaced); + state->color_mgmt_changed = replaced; + return ret; + } else if (property == config->gamma_lut_property) { + ret = drm_atomic_replace_property_blob_from_id(crtc, + &state->gamma_lut, + val, + -1, + &replaced); + state->color_mgmt_changed = replaced; + return ret; + } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); else return -EINVAL; @@ -456,6 +534,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = state->active; else if (property == config->prop_mode_id) *val = (state->mode_blob) ? state->mode_blob->base.id : 0; + else if (property == config->degamma_lut_property) + *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; + else if (property == config->ctm_property) + *val = (state->ctm) ? state->ctm->base.id : 0; + else if (property == config->gamma_lut_property) + *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7a034b231792..3e49a0993191 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2495,8 +2495,12 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) { - if (crtc->state) + if (crtc->state) { drm_property_unreference_blob(crtc->state->mode_blob); + drm_property_unreference_blob(crtc->state->degamma_lut); + drm_property_unreference_blob(crtc->state->ctm); + drm_property_unreference_blob(crtc->state->gamma_lut); + } kfree(crtc->state); crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); @@ -2520,10 +2524,17 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, if (state->mode_blob) drm_property_reference_blob(state->mode_blob); + if (state->degamma_lut) + drm_property_reference_blob(state->degamma_lut); + if (state->ctm) + drm_property_reference_blob(state->ctm); + if (state->gamma_lut) + drm_property_reference_blob(state->gamma_lut); state->mode_changed = false; state->active_changed = false; state->planes_changed = false; state->connectors_changed = false; + state->color_mgmt_changed = false; state->event = NULL; } EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); @@ -2564,6 +2575,9 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { drm_property_unreference_blob(state->mode_blob); + drm_property_unreference_blob(state->degamma_lut); + drm_property_unreference_blob(state->ctm); + drm_property_unreference_blob(state->gamma_lut); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); @@ -2877,3 +2891,97 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); + +/** + * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table + * @crtc: CRTC object + * @red: red correction table + * @green: green correction table + * @blue: green correction table + * @start: + * @size: size of the tables + * + * Implements support for legacy gamma correction table for drivers + * that support color management through the DEGAMMA_LUT/GAMMA_LUT + * properties. + */ +void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + uint32_t start, uint32_t size) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_property_blob *blob = NULL; + struct drm_color_lut *blob_data; + int i, ret = 0; + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return; + + blob = drm_property_create_blob(dev, + sizeof(struct drm_color_lut) * size, + NULL); + if (!blob) { + ret = -ENOMEM; + goto fail; + } + + /* Prepare GAMMA_LUT with the legacy values. */ + blob_data = (struct drm_color_lut *) blob->data; + for (i = 0; i < size; i++) { + blob_data[i].red = red[i]; + blob_data[i].green = green[i]; + blob_data[i].blue = blue[i]; + } + + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + /* Reset DEGAMMA_LUT and CTM properties. */ + ret = drm_atomic_crtc_set_property(crtc, crtc_state, + config->degamma_lut_property, 0); + if (ret) + goto fail; + + ret = drm_atomic_crtc_set_property(crtc, crtc_state, + config->ctm_property, 0); + if (ret) + goto fail; + + ret = drm_atomic_crtc_set_property(crtc, crtc_state, + config->gamma_lut_property, blob->base.id); + if (ret) + goto fail; + + ret = drm_atomic_commit(state); + if (ret) + goto fail; + + /* Driver takes ownership of state on successful commit. */ + + drm_property_unreference_blob(blob); + + return; +fail: + if (ret == -EDEADLK) + goto backoff; + + drm_atomic_state_free(state); + drm_property_unreference_blob(blob); + + return; +backoff: + drm_atomic_state_clear(state); + drm_atomic_legacy_backoff(state); + + goto retry; +} +EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 579505c0a498..49781a9f8a94 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1563,6 +1563,41 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_mode_id = prop; + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "DEGAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.degamma_lut_property = prop; + + prop = drm_property_create_range(dev, + DRM_MODE_PROP_IMMUTABLE, + "DEGAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.degamma_lut_size_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "CTM", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.ctm_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "GAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.gamma_lut_property = prop; + + prop = drm_property_create_range(dev, + DRM_MODE_PROP_IMMUTABLE, + "GAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.gamma_lut_size_property = prop; + return 0; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7539eea4ccbc..79555d2b1b87 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1075,3 +1075,36 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return drm_plane_helper_commit(plane, plane_state, old_fb); } EXPORT_SYMBOL(drm_helper_crtc_mode_set_base); + +/** + * drm_helper_crtc_enable_color_mgmt - enable color management properties + * @crtc: DRM CRTC + * @degamma_lut_size: the size of the degamma lut (before CSC) + * @gamma_lut_size: the size of the gamma lut (after CSC) + * + * This function lets the driver enable the color correction properties on a + * CRTC. This includes 3 degamma, csc and gamma properties that userspace can + * set and 2 size properties to inform the userspace of the lut sizes. + */ +void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc, + int degamma_lut_size, + int gamma_lut_size) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + drm_object_attach_property(&crtc->base, + config->degamma_lut_property, 0); + drm_object_attach_property(&crtc->base, + config->ctm_property, 0); + drm_object_attach_property(&crtc->base, + config->gamma_lut_property, 0); + + drm_object_attach_property(&crtc->base, + config->degamma_lut_size_property, + degamma_lut_size); + drm_object_attach_property(&crtc->base, + config->gamma_lut_size_property, + gamma_lut_size); +} +EXPORT_SYMBOL(drm_helper_crtc_enable_color_mgmt); |