summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_atomic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_atomic.c')
-rw-r--r--drivers/gpu/drm/drm_atomic.c552
1 files changed, 416 insertions, 136 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9ea2611770f4..080aec5a9774 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -26,7 +26,7 @@
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
-
+#include <linux/export.h>
#include <linux/sync_file.h>
#include <drm/drm_atomic.h>
@@ -42,6 +42,7 @@
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drm_writeback.h>
+#include <drm/drm_colorop.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -94,34 +95,35 @@ int drm_crtc_commit_wait(struct drm_crtc_commit *commit)
EXPORT_SYMBOL(drm_crtc_commit_wait);
/**
- * drm_atomic_state_default_release -
- * release memory initialized by drm_atomic_state_init
+ * drm_atomic_commit_default_release -
+ * release memory initialized by drm_atomic_commit_init
* @state: atomic state
*
- * Free all the memory allocated by drm_atomic_state_init.
+ * Free all the memory allocated by drm_atomic_commit_init.
* This should only be used by drivers which are still subclassing
- * &drm_atomic_state and haven't switched to &drm_private_state yet.
+ * &drm_atomic_commit and haven't switched to &drm_private_state yet.
*/
-void drm_atomic_state_default_release(struct drm_atomic_state *state)
+void drm_atomic_commit_default_release(struct drm_atomic_commit *state)
{
kfree(state->connectors);
kfree(state->crtcs);
kfree(state->planes);
+ kfree(state->colorops);
kfree(state->private_objs);
}
-EXPORT_SYMBOL(drm_atomic_state_default_release);
+EXPORT_SYMBOL(drm_atomic_commit_default_release);
/**
- * drm_atomic_state_init - init new atomic state
+ * drm_atomic_commit_init - init new atomic state
* @dev: DRM device
* @state: atomic state
*
* Default implementation for filling in a new atomic state.
* This should only be used by drivers which are still subclassing
- * &drm_atomic_state and haven't switched to &drm_private_state yet.
+ * &drm_atomic_commit and haven't switched to &drm_private_state yet.
*/
int
-drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
+drm_atomic_commit_init(struct drm_device *dev, struct drm_atomic_commit *state)
{
kref_init(&state->ref);
@@ -130,17 +132,20 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
*/
state->allow_modeset = true;
- state->crtcs = kcalloc(dev->mode_config.num_crtc,
- sizeof(*state->crtcs), GFP_KERNEL);
+ state->crtcs = kzalloc_objs(*state->crtcs, dev->mode_config.num_crtc);
if (!state->crtcs)
goto fail;
- state->planes = kcalloc(dev->mode_config.num_total_plane,
- sizeof(*state->planes), GFP_KERNEL);
+ state->planes = kzalloc_objs(*state->planes,
+ dev->mode_config.num_total_plane);
if (!state->planes)
goto fail;
+ state->colorops = kzalloc_objs(*state->colorops,
+ dev->mode_config.num_colorop);
+ if (!state->colorops)
+ goto fail;
/*
- * Because drm_atomic_state can be committed asynchronously we need our
+ * Because drm_atomic_commit can be committed asynchronously we need our
* own reference and cannot rely on the on implied by drm_file in the
* ioctl call.
*/
@@ -151,29 +156,29 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
return 0;
fail:
- drm_atomic_state_default_release(state);
+ drm_atomic_commit_default_release(state);
return -ENOMEM;
}
-EXPORT_SYMBOL(drm_atomic_state_init);
+EXPORT_SYMBOL(drm_atomic_commit_init);
/**
- * drm_atomic_state_alloc - allocate atomic state
+ * drm_atomic_commit_alloc - allocate atomic state
* @dev: DRM device
*
* This allocates an empty atomic state to track updates.
*/
-struct drm_atomic_state *
-drm_atomic_state_alloc(struct drm_device *dev)
+struct drm_atomic_commit *
+drm_atomic_commit_alloc(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
if (!config->funcs->atomic_state_alloc) {
- struct drm_atomic_state *state;
+ struct drm_atomic_commit *state;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc_obj(*state);
if (!state)
return NULL;
- if (drm_atomic_state_init(dev, state) < 0) {
+ if (drm_atomic_commit_init(dev, state) < 0) {
kfree(state);
return NULL;
}
@@ -182,17 +187,17 @@ drm_atomic_state_alloc(struct drm_device *dev)
return config->funcs->atomic_state_alloc(dev);
}
-EXPORT_SYMBOL(drm_atomic_state_alloc);
+EXPORT_SYMBOL(drm_atomic_commit_alloc);
/**
- * drm_atomic_state_default_clear - clear base atomic state
+ * drm_atomic_commit_default_clear - clear base atomic state
* @state: atomic state
*
* Default implementation for clearing atomic state.
* This should only be used by drivers which are still subclassing
- * &drm_atomic_state and haven't switched to &drm_private_state yet.
+ * &drm_atomic_commit and haven't switched to &drm_private_state yet.
*/
-void drm_atomic_state_default_clear(struct drm_atomic_state *state)
+void drm_atomic_commit_default_clear(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
@@ -200,6 +205,8 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
drm_dbg_atomic(dev, "Clearing atomic state %p\n", state);
+ state->checked = false;
+
for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i].ptr;
@@ -207,9 +214,9 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
connector->funcs->atomic_destroy_state(connector,
- state->connectors[i].state);
+ state->connectors[i].state_to_destroy);
state->connectors[i].ptr = NULL;
- state->connectors[i].state = NULL;
+ state->connectors[i].state_to_destroy = NULL;
state->connectors[i].old_state = NULL;
state->connectors[i].new_state = NULL;
drm_connector_put(connector);
@@ -222,10 +229,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
crtc->funcs->atomic_destroy_state(crtc,
- state->crtcs[i].state);
+ state->crtcs[i].state_to_destroy);
state->crtcs[i].ptr = NULL;
- state->crtcs[i].state = NULL;
+ state->crtcs[i].state_to_destroy = NULL;
state->crtcs[i].old_state = NULL;
state->crtcs[i].new_state = NULL;
@@ -242,20 +249,34 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
plane->funcs->atomic_destroy_state(plane,
- state->planes[i].state);
+ state->planes[i].state_to_destroy);
state->planes[i].ptr = NULL;
- state->planes[i].state = NULL;
+ state->planes[i].state_to_destroy = NULL;
state->planes[i].old_state = NULL;
state->planes[i].new_state = NULL;
}
+ for (i = 0; i < config->num_colorop; i++) {
+ struct drm_colorop *colorop = state->colorops[i].ptr;
+
+ if (!colorop)
+ continue;
+
+ drm_colorop_atomic_destroy_state(colorop,
+ state->colorops[i].state);
+ state->colorops[i].ptr = NULL;
+ state->colorops[i].state = NULL;
+ state->colorops[i].old_state = NULL;
+ state->colorops[i].new_state = NULL;
+ }
+
for (i = 0; i < state->num_private_objs; i++) {
struct drm_private_obj *obj = state->private_objs[i].ptr;
obj->funcs->atomic_destroy_state(obj,
- state->private_objs[i].state);
+ state->private_objs[i].state_to_destroy);
state->private_objs[i].ptr = NULL;
- state->private_objs[i].state = NULL;
+ state->private_objs[i].state_to_destroy = NULL;
state->private_objs[i].old_state = NULL;
state->private_objs[i].new_state = NULL;
}
@@ -266,10 +287,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
state->fake_commit = NULL;
}
}
-EXPORT_SYMBOL(drm_atomic_state_default_clear);
+EXPORT_SYMBOL(drm_atomic_commit_default_clear);
/**
- * drm_atomic_state_clear - clear state object
+ * drm_atomic_commit_clear - clear state object
* @state: atomic state
*
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
@@ -282,7 +303,7 @@ EXPORT_SYMBOL(drm_atomic_state_default_clear);
* Hence we must clear all cached state and completely start over, using this
* function.
*/
-void drm_atomic_state_clear(struct drm_atomic_state *state)
+void drm_atomic_commit_clear(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
@@ -290,37 +311,37 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
if (config->funcs->atomic_state_clear)
config->funcs->atomic_state_clear(state);
else
- drm_atomic_state_default_clear(state);
+ drm_atomic_commit_default_clear(state);
}
-EXPORT_SYMBOL(drm_atomic_state_clear);
+EXPORT_SYMBOL(drm_atomic_commit_clear);
/**
- * __drm_atomic_state_free - free all memory for an atomic state
+ * __drm_atomic_commit_free - free all memory for an atomic state
* @ref: This atomic state to deallocate
*
* This frees all memory associated with an atomic state, including all the
* per-object state for planes, CRTCs and connectors.
*/
-void __drm_atomic_state_free(struct kref *ref)
+void __drm_atomic_commit_free(struct kref *ref)
{
- struct drm_atomic_state *state = container_of(ref, typeof(*state), ref);
+ struct drm_atomic_commit *state = container_of(ref, typeof(*state), ref);
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
- drm_atomic_state_clear(state);
+ drm_atomic_commit_clear(state);
drm_dbg_atomic(state->dev, "Freeing atomic state %p\n", state);
if (config->funcs->atomic_state_free) {
config->funcs->atomic_state_free(state);
} else {
- drm_atomic_state_default_release(state);
+ drm_atomic_commit_default_release(state);
kfree(state);
}
drm_dev_put(dev);
}
-EXPORT_SYMBOL(__drm_atomic_state_free);
+EXPORT_SYMBOL(__drm_atomic_commit_free);
/**
* drm_atomic_get_crtc_state - get CRTC state
@@ -332,7 +353,7 @@ EXPORT_SYMBOL(__drm_atomic_state_free);
* is consistent.
*
* WARNING: Drivers may only add new CRTC states to a @state if
- * drm_atomic_state.allow_modeset is set, or if it's a driver-internal commit
+ * drm_atomic_commit.allow_modeset is set, or if it's a driver-internal commit
* not created by userspace through an IOCTL call.
*
* Returns:
@@ -341,15 +362,16 @@ EXPORT_SYMBOL(__drm_atomic_state_free);
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_crtc_state *
-drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+drm_atomic_get_crtc_state(struct drm_atomic_commit *state,
struct drm_crtc *crtc)
{
int ret, index = drm_crtc_index(crtc);
struct drm_crtc_state *crtc_state;
WARN_ON(!state->acquire_ctx);
+ drm_WARN_ON(state->dev, state->checked);
- crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (crtc_state)
return crtc_state;
@@ -361,7 +383,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
if (!crtc_state)
return ERR_PTR(-ENOMEM);
- state->crtcs[index].state = crtc_state;
+ state->crtcs[index].state_to_destroy = crtc_state;
state->crtcs[index].old_state = crtc->state;
state->crtcs[index].new_state = crtc_state;
state->crtcs[index].ptr = crtc;
@@ -441,18 +463,19 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
struct drm_crtc *crtc = state->crtc;
drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
- drm_printf(p, "\tenable=%d\n", state->enable);
- drm_printf(p, "\tactive=%d\n", state->active);
- drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
- drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
- drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
- drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
- drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed);
- drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
- drm_printf(p, "\tplane_mask=%x\n", state->plane_mask);
- drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask);
- drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask);
- drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
+ drm_printf_indent(p, 1, "enable=%d\n", state->enable);
+ drm_printf_indent(p, 1, "active=%d\n", state->active);
+ drm_printf_indent(p, 1, "self_refresh_active=%d\n", state->self_refresh_active);
+ drm_printf_indent(p, 1, "planes_changed=%d\n", state->planes_changed);
+ drm_printf_indent(p, 1, "mode_changed=%d\n", state->mode_changed);
+ drm_printf_indent(p, 1, "active_changed=%d\n", state->active_changed);
+ drm_printf_indent(p, 1, "connectors_changed=%d\n", state->connectors_changed);
+ drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed);
+ drm_printf_indent(p, 1, "plane_mask=%x\n", state->plane_mask);
+ drm_printf_indent(p, 1, "connector_mask=%x\n", state->connector_mask);
+ drm_printf_indent(p, 1, "encoder_mask=%x\n", state->encoder_mask);
+ drm_printf_indent(p, 1, "mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
+ drm_printf_indent(p, 1, "background_color=%llx\n", state->background_color);
if (crtc->funcs->atomic_print_state)
crtc->funcs->atomic_print_state(p, state);
@@ -480,8 +503,8 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
}
if (state->crtc)
- crtc_state = drm_atomic_get_existing_crtc_state(state->state,
- state->crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state->state,
+ state->crtc);
if (writeback_job->fb && !crtc_state->active) {
drm_dbg_atomic(connector->dev,
@@ -521,20 +544,21 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_plane_state *
-drm_atomic_get_plane_state(struct drm_atomic_state *state,
+drm_atomic_get_plane_state(struct drm_atomic_commit *state,
struct drm_plane *plane)
{
int ret, index = drm_plane_index(plane);
struct drm_plane_state *plane_state;
WARN_ON(!state->acquire_ctx);
+ drm_WARN_ON(state->dev, state->checked);
/* the legacy pointers should never be set */
WARN_ON(plane->fb);
WARN_ON(plane->old_fb);
WARN_ON(plane->crtc);
- plane_state = drm_atomic_get_existing_plane_state(state, plane);
+ plane_state = drm_atomic_get_new_plane_state(state, plane);
if (plane_state)
return plane_state;
@@ -546,7 +570,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
if (!plane_state)
return ERR_PTR(-ENOMEM);
- state->planes[index].state = plane_state;
+ state->planes[index].state_to_destroy = plane_state;
state->planes[index].ptr = plane;
state->planes[index].old_state = plane->state;
state->planes[index].new_state = plane_state;
@@ -568,6 +592,87 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
}
EXPORT_SYMBOL(drm_atomic_get_plane_state);
+/**
+ * drm_atomic_get_colorop_state - get colorop state
+ * @state: global atomic state object
+ * @colorop: colorop to get state object for
+ *
+ * This function returns the colorop state for the given colorop, allocating it
+ * if needed. It will also grab the relevant plane lock to make sure that the
+ * state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_colorop_state *
+drm_atomic_get_colorop_state(struct drm_atomic_commit *state,
+ struct drm_colorop *colorop)
+{
+ int ret, index = drm_colorop_index(colorop);
+ struct drm_colorop_state *colorop_state;
+
+ WARN_ON(!state->acquire_ctx);
+
+ colorop_state = drm_atomic_get_new_colorop_state(state, colorop);
+ if (colorop_state)
+ return colorop_state;
+
+ ret = drm_modeset_lock(&colorop->plane->mutex, state->acquire_ctx);
+ if (ret)
+ return ERR_PTR(ret);
+
+ colorop_state = drm_atomic_helper_colorop_duplicate_state(colorop);
+ if (!colorop_state)
+ return ERR_PTR(-ENOMEM);
+
+ state->colorops[index].state = colorop_state;
+ state->colorops[index].ptr = colorop;
+ state->colorops[index].old_state = colorop->state;
+ state->colorops[index].new_state = colorop_state;
+ colorop_state->state = state;
+
+ drm_dbg_atomic(colorop->dev, "Added [COLOROP:%d:%d] %p state to %p\n",
+ colorop->base.id, colorop->type, colorop_state, state);
+
+ return colorop_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_colorop_state);
+
+/**
+ * drm_atomic_get_old_colorop_state - get colorop state, if it exists
+ * @state: global atomic state object
+ * @colorop: colorop to grab
+ *
+ * This function returns the old colorop state for the given colorop, or
+ * NULL if the colorop is not part of the global atomic state.
+ */
+struct drm_colorop_state *
+drm_atomic_get_old_colorop_state(struct drm_atomic_commit *state,
+ struct drm_colorop *colorop)
+{
+ return state->colorops[drm_colorop_index(colorop)].old_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_colorop_state);
+
+/**
+ * drm_atomic_get_new_colorop_state - get colorop state, if it exists
+ * @state: global atomic state object
+ * @colorop: colorop to grab
+ *
+ * This function returns the new colorop state for the given colorop, or
+ * NULL if the colorop is not part of the global atomic state.
+ */
+struct drm_colorop_state *
+drm_atomic_get_new_colorop_state(struct drm_atomic_commit *state,
+ struct drm_colorop *colorop)
+{
+ return state->colorops[drm_colorop_index(colorop)].new_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_colorop_state);
+
static bool
plane_switching_crtc(const struct drm_plane_state *old_plane_state,
const struct drm_plane_state *new_plane_state)
@@ -707,6 +812,46 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
return 0;
}
+static void drm_atomic_colorop_print_state(struct drm_printer *p,
+ const struct drm_colorop_state *state)
+{
+ struct drm_colorop *colorop = state->colorop;
+
+ drm_printf(p, "colorop[%u]:\n", colorop->base.id);
+ drm_printf_indent(p, 1, "type=%s\n", drm_get_colorop_type_name(colorop->type));
+ if (colorop->bypass_property)
+ drm_printf_indent(p, 1, "bypass=%u\n", state->bypass);
+
+ switch (colorop->type) {
+ case DRM_COLOROP_1D_CURVE:
+ drm_printf_indent(p, 1, "curve_1d_type=%s\n",
+ drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+ break;
+ case DRM_COLOROP_1D_LUT:
+ drm_printf_indent(p, 1, "size=%d\n", colorop->size);
+ drm_printf_indent(p, 1, "interpolation=%s\n",
+ drm_get_colorop_lut1d_interpolation_name(state->lut1d_interpolation));
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
+ break;
+ case DRM_COLOROP_CTM_3X4:
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
+ break;
+ case DRM_COLOROP_MULTIPLIER:
+ drm_printf_indent(p, 1, "multiplier=%llu\n", state->multiplier);
+ break;
+ case DRM_COLOROP_3D_LUT:
+ drm_printf_indent(p, 1, "size=%d\n", colorop->size);
+ drm_printf_indent(p, 1, "interpolation=%s\n",
+ drm_get_colorop_lut3d_interpolation_name(state->lut3d_interpolation));
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
+ break;
+ default:
+ break;
+ }
+
+ drm_printf_indent(p, 1, "next=%d\n", colorop->next ? colorop->next->base.id : 0);
+}
+
static void drm_atomic_plane_print_state(struct drm_printer *p,
const struct drm_plane_state *state)
{
@@ -715,20 +860,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
struct drm_rect dest = drm_plane_state_dest(state);
drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name);
- drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
- drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0);
+ drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)");
+ drm_printf_indent(p, 1, "fb=%u\n", state->fb ? state->fb->base.id : 0);
if (state->fb)
drm_framebuffer_print_info(p, 2, state->fb);
- drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
- drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
- drm_printf(p, "\trotation=%x\n", state->rotation);
- drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos);
- drm_printf(p, "\tcolor-encoding=%s\n",
- drm_get_color_encoding_name(state->color_encoding));
- drm_printf(p, "\tcolor-range=%s\n",
- drm_get_color_range_name(state->color_range));
- drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
-
+ drm_printf_indent(p, 1, "crtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
+ drm_printf_indent(p, 1, "src-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
+ drm_printf_indent(p, 1, "rotation=%x\n", state->rotation);
+ drm_printf_indent(p, 1, "normalized-zpos=%x\n", state->normalized_zpos);
+ drm_printf_indent(p, 1, "color-encoding=%s\n",
+ drm_get_color_encoding_name(state->color_encoding));
+ drm_printf_indent(p, 1, "color-range=%s\n",
+ drm_get_color_range_name(state->color_range));
+ drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed);
+ drm_printf_indent(p, 1, "color-pipeline=%d\n",
+ state->color_pipeline ? state->color_pipeline->base.id : 0);
if (plane->funcs->atomic_print_state)
plane->funcs->atomic_print_state(p, state);
}
@@ -755,9 +901,9 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
* directly. Sequence of the actual hardware state commit is not handled,
* drivers might need to keep track of struct drm_crtc_commit within subclassed
* structure of &drm_private_state as necessary, e.g. similar to
- * &drm_plane_state.commit. See also &drm_atomic_state.fake_commit.
+ * &drm_plane_state.commit. See also &drm_atomic_commit.fake_commit.
*
- * All private state structures contained in a &drm_atomic_state update can be
+ * All private state structures contained in a &drm_atomic_commit update can be
* iterated using for_each_oldnew_private_obj_in_state(),
* for_each_new_private_obj_in_state() and for_each_old_private_obj_in_state().
* Drivers are recommended to wrap these for each type of driver private state
@@ -765,7 +911,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
* least if they want to iterate over all objects of a given type.
*
* An earlier way to handle driver private state was by subclassing struct
- * &drm_atomic_state. But since that encourages non-standard ways to implement
+ * &drm_atomic_commit. But since that encourages non-standard ways to implement
* the check/commit split atomic requires (by using e.g. "check and rollback or
* commit instead" of "duplicate state, check, then either commit or release
* duplicated state) it is deprecated in favour of using &drm_private_state.
@@ -775,28 +921,35 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
* drm_atomic_private_obj_init - initialize private object
* @dev: DRM device this object will be attached to
* @obj: private object
- * @state: initial private object state
* @funcs: pointer to the struct of function pointers that identify the object
* type
*
* Initialize the private object, which can be embedded into any
* driver private object that needs its own atomic state.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
*/
-void
-drm_atomic_private_obj_init(struct drm_device *dev,
- struct drm_private_obj *obj,
- struct drm_private_state *state,
- const struct drm_private_state_funcs *funcs)
+int drm_atomic_private_obj_init(struct drm_device *dev,
+ struct drm_private_obj *obj,
+ const struct drm_private_state_funcs *funcs)
{
+ struct drm_private_state *state;
memset(obj, 0, sizeof(*obj));
drm_modeset_lock_init(&obj->lock);
- obj->state = state;
+ obj->dev = dev;
obj->funcs = funcs;
list_add_tail(&obj->head, &dev->mode_config.privobj_list);
- state->obj = obj;
+ state = obj->funcs->atomic_create_state(obj);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ obj->state = state;
+
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_private_obj_init);
@@ -828,17 +981,20 @@ EXPORT_SYMBOL(drm_atomic_private_obj_fini);
* Either the allocated state or the error code encoded into a pointer.
*/
struct drm_private_state *
-drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
+drm_atomic_get_private_obj_state(struct drm_atomic_commit *state,
struct drm_private_obj *obj)
{
- int index, num_objs, i, ret;
+ int index, num_objs, ret;
size_t size;
struct __drm_private_objs_state *arr;
struct drm_private_state *obj_state;
- for (i = 0; i < state->num_private_objs; i++)
- if (obj == state->private_objs[i].ptr)
- return state->private_objs[i].state;
+ WARN_ON(!state->acquire_ctx);
+ drm_WARN_ON(state->dev, state->checked);
+
+ obj_state = drm_atomic_get_new_private_obj_state(state, obj);
+ if (obj_state)
+ return obj_state;
ret = drm_modeset_lock(&obj->lock, state->acquire_ctx);
if (ret)
@@ -858,7 +1014,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
if (!obj_state)
return ERR_PTR(-ENOMEM);
- state->private_objs[index].state = obj_state;
+ state->private_objs[index].state_to_destroy = obj_state;
state->private_objs[index].old_state = obj->state;
state->private_objs[index].new_state = obj_state;
state->private_objs[index].ptr = obj;
@@ -883,7 +1039,7 @@ EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
-drm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state,
+drm_atomic_get_old_private_obj_state(const struct drm_atomic_commit *state,
struct drm_private_obj *obj)
{
int i;
@@ -905,7 +1061,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
-drm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state,
+drm_atomic_get_new_private_obj_state(const struct drm_atomic_commit *state,
struct drm_private_obj *obj)
{
int i;
@@ -933,11 +1089,14 @@ EXPORT_SYMBOL(drm_atomic_get_new_private_obj_state);
* state). This is especially true in enable hooks because the pipeline has
* changed.
*
+ * If you don't have access to the atomic state, see
+ * drm_atomic_get_connector_for_encoder().
+ *
* Returns: The old connector connected to @encoder, or NULL if the encoder is
* not connected.
*/
struct drm_connector *
-drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
+drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_commit *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@@ -967,11 +1126,14 @@ EXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder);
* attached to @encoder vs ones that do (and to inspect their state). This is
* especially true in disable hooks because the pipeline will change.
*
+ * If you don't have access to the atomic state, see
+ * drm_atomic_get_connector_for_encoder().
+ *
* Returns: The new connector connected to @encoder, or NULL if the encoder is
* not connected.
*/
struct drm_connector *
-drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
+drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_commit *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@@ -988,6 +1150,59 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
/**
+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
+ * @encoder: The encoder to find the connector of
+ * @ctx: Modeset locking context
+ *
+ * This function finds and returns the connector currently assigned to
+ * an @encoder.
+ *
+ * It is similar to the drm_atomic_get_old_connector_for_encoder() and
+ * drm_atomic_get_new_connector_for_encoder() helpers, but doesn't
+ * require access to the atomic state. If you have access to it, prefer
+ * using these. This helper is typically useful in situations where you
+ * don't have access to the atomic state, like detect, link repair,
+ * threaded interrupt handlers, or hooks from other frameworks (ALSA,
+ * CEC, etc.).
+ *
+ * Returns:
+ * The connector connected to @encoder, or an error pointer otherwise.
+ * When the error is EDEADLK, a deadlock has been detected and the
+ * sequence must be restarted.
+ */
+struct drm_connector *
+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
+ struct drm_connector *connector;
+ struct drm_device *dev = encoder->dev;
+ int ret;
+
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (!connector->state)
+ continue;
+
+ if (encoder == connector->state->best_encoder) {
+ out_connector = connector;
+ break;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+ return out_connector;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_for_encoder);
+
+
+/**
* drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
* @state: Atomic state
* @encoder: The encoder to fetch the crtc state for
@@ -999,7 +1214,7 @@ EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
* not connected.
*/
struct drm_crtc *
-drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_commit *state,
struct drm_encoder *encoder)
{
struct drm_connector *connector;
@@ -1029,7 +1244,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
* not connected.
*/
struct drm_crtc *
-drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_commit *state,
struct drm_encoder *encoder)
{
struct drm_connector *connector;
@@ -1062,7 +1277,7 @@ EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_connector_state *
-drm_atomic_get_connector_state(struct drm_atomic_state *state,
+drm_atomic_get_connector_state(struct drm_atomic_commit *state,
struct drm_connector *connector)
{
int ret, index;
@@ -1070,6 +1285,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
struct drm_connector_state *connector_state;
WARN_ON(!state->acquire_ctx);
+ drm_WARN_ON(state->dev, state->checked);
ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
if (ret)
@@ -1093,15 +1309,16 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
state->num_connector = alloc;
}
- if (state->connectors[index].state)
- return state->connectors[index].state;
+ connector_state = drm_atomic_get_new_connector_state(state, connector);
+ if (connector_state)
+ return connector_state;
connector_state = connector->funcs->atomic_duplicate_state(connector);
if (!connector_state)
return ERR_PTR(-ENOMEM);
drm_connector_get(connector);
- state->connectors[index].state = connector_state;
+ state->connectors[index].state_to_destroy = connector_state;
state->connectors[index].old_state = connector->state;
state->connectors[index].new_state = connector_state;
state->connectors[index].ptr = connector;
@@ -1130,27 +1347,27 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
struct drm_connector *connector = state->connector;
drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
- drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
- drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
- drm_printf(p, "\tinterlace_allowed=%d\n", connector->interlace_allowed);
- drm_printf(p, "\tycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed);
- drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
- drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace));
+ drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)");
+ drm_printf_indent(p, 1, "self_refresh_aware=%d\n", state->self_refresh_aware);
+ drm_printf_indent(p, 1, "interlace_allowed=%d\n", connector->interlace_allowed);
+ drm_printf_indent(p, 1, "ycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed);
+ drm_printf_indent(p, 1, "max_requested_bpc=%d\n", state->max_requested_bpc);
+ drm_printf_indent(p, 1, "colorspace=%s\n", drm_get_colorspace_name(state->colorspace));
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
- drm_printf(p, "\tbroadcast_rgb=%s\n",
- drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
- drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n');
- drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
- drm_printf(p, "\toutput_format=%s\n",
- drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
- drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
+ drm_printf_indent(p, 1, "broadcast_rgb=%s\n",
+ drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
+ drm_printf_indent(p, 1, "is_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n');
+ drm_printf_indent(p, 1, "output_bpc=%u\n", state->hdmi.output_bpc);
+ drm_printf_indent(p, 1, "output_format=%s\n",
+ drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
+ drm_printf_indent(p, 1, "tmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
}
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
if (state->writeback_job && state->writeback_job->fb)
- drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id);
+ drm_printf_indent(p, 1, "fb=%d\n", state->writeback_job->fb->base.id);
if (connector->funcs->atomic_print_state)
connector->funcs->atomic_print_state(p, state);
@@ -1171,7 +1388,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
* entire atomic sequence must be restarted.
*/
struct drm_bridge_state *
-drm_atomic_get_bridge_state(struct drm_atomic_state *state,
+drm_atomic_get_bridge_state(struct drm_atomic_commit *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@@ -1193,7 +1410,7 @@ EXPORT_SYMBOL(drm_atomic_get_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
-drm_atomic_get_old_bridge_state(const struct drm_atomic_state *state,
+drm_atomic_get_old_bridge_state(const struct drm_atomic_commit *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@@ -1215,7 +1432,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
-drm_atomic_get_new_bridge_state(const struct drm_atomic_state *state,
+drm_atomic_get_new_bridge_state(const struct drm_atomic_commit *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@@ -1245,11 +1462,10 @@ EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
* sequence must be restarted. All other errors are fatal.
*/
int
-drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
+drm_atomic_add_encoder_bridges(struct drm_atomic_commit *state,
struct drm_encoder *encoder)
{
struct drm_bridge_state *bridge_state;
- struct drm_bridge *bridge;
if (!encoder)
return 0;
@@ -1258,7 +1474,7 @@ drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
"Adding all bridges for [encoder:%d:%s] to %p\n",
encoder->base.id, encoder->name, state);
- drm_for_each_bridge_in_chain(encoder, bridge) {
+ drm_for_each_bridge_in_chain_scoped(encoder, bridge) {
/* Skip bridges that don't implement the atomic state hooks. */
if (!bridge->funcs->atomic_duplicate_state)
continue;
@@ -1290,7 +1506,7 @@ EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
* sequence must be restarted. All other errors are fatal.
*/
int
-drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+drm_atomic_add_affected_connectors(struct drm_atomic_commit *state,
struct drm_crtc *crtc)
{
struct drm_mode_config *config = &state->dev->mode_config;
@@ -1354,12 +1570,13 @@ EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
* sequence must be restarted. All other errors are fatal.
*/
int
-drm_atomic_add_affected_planes(struct drm_atomic_state *state,
+drm_atomic_add_affected_planes(struct drm_atomic_commit *state,
struct drm_crtc *crtc)
{
const struct drm_crtc_state *old_crtc_state =
drm_atomic_get_old_crtc_state(state, crtc);
struct drm_plane *plane;
+ int ret;
WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));
@@ -1373,12 +1590,64 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
if (IS_ERR(plane_state))
return PTR_ERR(plane_state);
+
+ if (plane_state->color_pipeline) {
+ ret = drm_atomic_add_affected_colorops(state, plane);
+ if (ret)
+ return ret;
+ }
}
return 0;
}
EXPORT_SYMBOL(drm_atomic_add_affected_planes);
/**
+ * drm_atomic_add_affected_colorops - add colorops for plane
+ * @state: atomic state
+ * @plane: DRM plane
+ *
+ * This function walks the current configuration and adds all colorops
+ * currently used by @plane to the atomic configuration @state. This is useful
+ * when an atomic commit also needs to check all currently enabled colorop on
+ * @plane, e.g. when changing the mode. It's also useful when re-enabling a plane
+ * to avoid special code to force-enable all colorops.
+ *
+ * Since acquiring a colorop state will always also acquire the w/w mutex of the
+ * current plane for that colorop (if there is any) adding all the colorop states for
+ * a plane will not reduce parallelism of atomic updates.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_colorops(struct drm_atomic_commit *state,
+ struct drm_plane *plane)
+{
+ struct drm_colorop *colorop;
+ struct drm_colorop_state *colorop_state;
+
+ WARN_ON(!drm_atomic_get_new_plane_state(state, plane));
+
+ drm_dbg_atomic(plane->dev,
+ "Adding all current colorops for [PLANE:%d:%s] to %p\n",
+ plane->base.id, plane->name, state);
+
+ drm_for_each_colorop(colorop, plane->dev) {
+ if (colorop->plane != plane)
+ continue;
+
+ colorop_state = drm_atomic_get_colorop_state(state, colorop);
+ if (IS_ERR(colorop_state))
+ return PTR_ERR(colorop_state);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_colorops);
+
+/**
* drm_atomic_check_only - check whether a given config would work
* @state: atomic configuration to check
*
@@ -1389,7 +1658,7 @@ EXPORT_SYMBOL(drm_atomic_add_affected_planes);
* Returns:
* 0 on success, negative error code on failure.
*/
-int drm_atomic_check_only(struct drm_atomic_state *state)
+int drm_atomic_check_only(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
@@ -1482,6 +1751,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
requested_crtc, affected_crtc);
}
+ state->checked = true;
+
return 0;
}
EXPORT_SYMBOL(drm_atomic_check_only);
@@ -1495,12 +1766,12 @@ EXPORT_SYMBOL(drm_atomic_check_only);
* backoff dance and restart. All other errors are fatal.
*
* This function will take its own reference on @state.
- * Callers should always release their reference with drm_atomic_state_put().
+ * Callers should always release their reference with drm_atomic_commit_put().
*
* Returns:
* 0 on success, negative error code on failure.
*/
-int drm_atomic_commit(struct drm_atomic_state *state)
+int drm_atomic_commit(struct drm_atomic_commit *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
struct drm_printer p = drm_info_printer(state->dev->dev);
@@ -1528,12 +1799,12 @@ EXPORT_SYMBOL(drm_atomic_commit);
* backoff dance and restart. All other errors are fatal.
*
* This function will take its own reference on @state.
- * Callers should always release their reference with drm_atomic_state_put().
+ * Callers should always release their reference with drm_atomic_commit_put().
*
* Returns:
* 0 on success, negative error code on failure.
*/
-int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
+int drm_atomic_nonblocking_commit(struct drm_atomic_commit *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
int ret;
@@ -1572,7 +1843,7 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
}
EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
-static int update_output_state(struct drm_atomic_state *state,
+static int update_output_state(struct drm_atomic_commit *state,
struct drm_mode_set *set)
{
struct drm_device *dev = set->crtc->dev;
@@ -1642,7 +1913,7 @@ static int update_output_state(struct drm_atomic_state *state,
/* just used from drm-client and atomic-helper: */
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *crtc_state;
struct drm_plane_state *primary_state;
@@ -1736,7 +2007,7 @@ static void drm_atomic_private_obj_print_state(struct drm_printer *p,
* Note that this function looks into the new state objects and hence its not
* safe to be used after the call to drm_atomic_helper_commit_hw_done().
*/
-void drm_atomic_print_new_state(const struct drm_atomic_state *state,
+void drm_atomic_print_new_state(const struct drm_atomic_commit *state,
struct drm_printer *p)
{
struct drm_plane *plane;
@@ -1774,6 +2045,7 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
bool take_locks)
{
struct drm_mode_config *config = &dev->mode_config;
+ struct drm_colorop *colorop;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_connector *connector;
@@ -1783,6 +2055,14 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
if (!drm_drv_uses_atomic_modeset(dev))
return;
+ list_for_each_entry(colorop, &config->colorop_list, head) {
+ if (take_locks)
+ drm_modeset_lock(&colorop->plane->mutex, NULL);
+ drm_atomic_colorop_print_state(p, colorop->state);
+ if (take_locks)
+ drm_modeset_unlock(&colorop->plane->mutex);
+ }
+
list_for_each_entry(plane, &config->plane_list, head) {
if (take_locks)
drm_modeset_lock(&plane->mutex, NULL);