/*
* Copyright (C) 2014 Red Hat
* Copyright (C) 2014 Intel Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Rob Clark <robdclark@gmail.com>
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_plane_helper.h>
/**
* drm_atomic_state_default_release -
* release memory initialized by drm_atomic_state_init
* @state: atomic state
*
* Free all the memory allocated by drm_atomic_state_init.
* This is useful for drivers that subclass the atomic state.
*/
void drm_atomic_state_default_release(struct drm_atomic_state *state)
{
kfree(state->connectors);
kfree(state->connector_states);
kfree(state->crtcs);
kfree(state->crtc_states);
kfree(state->planes);
kfree(state->plane_states);
}
EXPORT_SYMBOL(drm_atomic_state_default_release);
/**
* drm_atomic_state_init - init new atomic state
* @dev: DRM device
* @state: atomic state
*
* Default implementation for filling in a new atomic state.
* This is useful for drivers that subclass the atomic state.
*/
int
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
{
/* TODO legacy paths should maybe do a better job about
* setting this appropriately?
*/
state->allow_modeset = true;
state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
state->crtcs = kcalloc(dev->mode_config.num_crtc,
sizeof(*state->crtcs), GFP_KERNEL);
if (!state->crtcs)
goto fail;
state->crtc_states = kcalloc(dev->mode_config.num_crtc,
sizeof(*state->crtc_states), GFP_KERNEL);
if (!state->crtc_states)
goto fail;
state->planes = kcalloc(dev->mode_config.num_total_plane,
sizeof(*state->planes), GFP_KERNEL);
if (!state->planes)
goto fail;
state->plane_states = kcalloc(dev->mode_config.num_total_plane,
sizeof(*state->plane_states), GFP_KERNEL);
if (!state->plane_states)
goto fail;
state->connectors = kcalloc(state->num_connector,
sizeof(*state->connectors),
GFP_KERNEL);
if (!state->connectors)
goto fail;
state->connector_states = kcalloc(state->num_connector,
sizeof(*state->connector_states),
GFP_KERNEL);
if (!state->connector_states)
goto fail;
state->dev = dev;
DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
return 0;
fail:
drm_atomic_state_default_release(state);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_atomic_state_init);
/**
* drm_atomic_state_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_mode_config *config = &dev->mode_config;
struct drm_atomic_state *state;
if (!config->funcs->atomic_state_alloc) {
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
if (drm_atomic_state_init(dev, state) < 0) {
kfree(state);
return NULL;
}
return state;
}
return config->funcs->atomic_state_alloc(dev);
}
EXPORT_SYMBOL(drm_atomic_state_alloc);
/**
* drm_atomic_state_default_clear - clear base atomic state
* @state: atomic state
*
* Default implementation for clearing atomic state.
* This is useful for drivers that subclass the atomic state.
*/
void drm_atomic_state_default_clear(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
int i;
DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i];
if (!connector)
continue;
/*
* FIXME: Async commits can race with connector unplugging and
* there's currently nothing that prevents cleanup up state for
* deleted connectors. As long as the callback doesn't look at
* the connector we'll be fine though, so make sure that's the
* case by setting all connector point
|