#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_writeback.h>
#include <linux/slab.h>
#include <linux/dma-fence.h>
void
__drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state,
struct drm_crtc *crtc)
{
crtc_state->crtc = crtc;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset);
void
__drm_atomic_helper_crtc_reset(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
{
if (crtc_state)
__drm_atomic_helper_crtc_state_reset(crtc_state, crtc);
if (drm_dev_has_vblank(crtc->dev))
drm_crtc_vblank_reset(crtc);
crtc->state = crtc_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_reset);
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
struct drm_crtc_state *crtc_state =
kzalloc(sizeof(*crtc->state), GFP_KERNEL);
if (crtc->state)
crtc->funcs->atomic_destroy_state(crtc, crtc->state);
__drm_atomic_helper_crtc_reset(crtc, crtc_state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
memcpy(state, crtc->state, sizeof(*state));
if (state->mode_blob)
drm_property_blob_get(state->mode_blob);
if (state->degamma_lut)
drm_property_blob_get(state->degamma_lut);
if (state->ctm)
drm_property_blob_get(state->ctm);
if (state->gamma_lut)
drm_property_blob_get(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->zpos_changed = false;
state->commit = NULL;
state->event = NULL;
state->async_flip = false;
state->active = drm_atomic_crtc_effectively_active(state);
state->self_refresh_active = false;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
struct drm_crtc_state *
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct drm_crtc_state *state;
if (WARN_ON(!crtc->state))
return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_crtc_duplicate_state(crtc, state);
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
{
if (state->commit) {
if (state->event && state->commit->abort_completion)
drm_crtc_commit_put(state->commit);
kfree(state->commit->event);
state->commit->event = NULL;
drm_crtc_commit_put(state->commit);
}
drm_property_blob_put(state->mode_blob);
drm_property_blob_put(state->degamma_lut);
drm_property_blob_put(state->ctm);
drm_property_blob_put(state->gamma_lut);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
__drm_atomic_helper_crtc_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state,
struct drm_plane *plane)
{
u64 val;
plane_state->plane = plane;
plane_state->rotation = DRM_MODE_ROTATE_0;
plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE;
plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
if (plane->color_encoding_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->color_encoding_property,
&val))
plane_state->color_encoding = val;
}
if (plane->color_range_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->color_range_property,
&val))
plane_state->color_range = val;
}
if (plane->zpos_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->zpos_property,
&val)) {
plane_state->zpos = val;
plane_state->normalized_zpos = val;
}
}
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
struct drm_plane_state *plane_state)
{
if (plane_state)
__drm_atomic_helper_plane_state_reset(plane_state, plane);
plane->state = plane_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
void drm_atomic_helper_plane_reset(struct drm_plane *plane)
{
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
if (plane->state)
__drm_atomic_helper_plane_reset(plane, plane->state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
memcpy(state, plane->state, sizeof(*state));
if (state->fb)
drm_framebuffer_get(state->fb);
state->fence = NULL;
state->commit = NULL;
state->fb_damage_clips = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
struct drm_plane_state *
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
{
struct drm_plane_state *state;
if (WARN_ON(!plane->state))
return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_plane_duplicate_state(plane, state);
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
{
if (state->fb)
drm_framebuffer_put(state->fb);
if (state->fence)
dma_fence_put(state->fence);
if (state->commit)
drm_crtc_commit_put(state->commit);
drm_property_blob_put(state->fb_damage_clips);
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
__drm_atomic_helper_plane_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
void
__drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state,
struct drm_connector *connector)
{
conn_state->connector = connector;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_state_reset);
void
__drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state)
{
if (conn_state)
__drm_atomic_helper_connector_state_reset(conn_state, connector);
connector->state = conn_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
void drm_atomic_helper_connector_reset(struct drm_connector *connector)
{
struct drm_connector_state *conn_state =
kzalloc(sizeof(*conn_state), GFP_KERNEL);
if (connector->state)
__drm_atomic_helper_connector_destroy_state(connector->state);
kfree(connector->state);
__drm_atomic_helper_connector_reset(connector, conn_state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector)
{
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
struct drm_connector_state *state = connector->state;
state->tv.margins.left = cmdline->tv_margins.left;
state->tv.margins.right = cmdline->tv_margins.right;
state->tv.margins.top = cmdline->tv_margins.top;
state->tv.margins.bottom = cmdline->tv_margins.bottom;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
struct drm_connector_state *state = connector->state;
struct drm_property *prop;
uint64_t val;
prop = dev->mode_config.tv_mode_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.mode = val;
if (cmdline->tv_mode_specified)
state->tv.mode = cmdline->tv_mode;
prop = dev->mode_config.tv_select_subconnector_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.select_subconnector = val;
prop = dev->mode_config.tv_subconnector_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.subconnector = val;
prop = dev->mode_config.tv_brightness_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.brightness = val;
prop = dev->mode_config.tv_contrast_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.contrast = val;
prop = dev->mode_config.tv_flicker_reduction_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.flicker_reduction = val;
prop = dev->mode_config.tv_overscan_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.overscan = val;
prop = dev->mode_config.tv_saturation_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.saturation = val;
prop = dev->mode_config.tv_hue_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.hue = val;
drm_atomic_helper_connector_tv_margins_reset(connector);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, connector);
struct drm_connector_state *new_conn_state =
drm_atomic_get_new_connector_state(state, connector);
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
crtc = new_conn_state->crtc;
if (!crtc)
return 0;
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (!crtc_state)
return -EINVAL;
if (old_conn_state->tv.mode != new_conn_state->tv.mode)
crtc_state->mode_changed = true;
if (old_conn_state->tv.margins.left != new_conn_state->tv.margins.left ||
old_conn_state->tv.margins.right != new_conn_state->tv.margins.right ||
old_conn_state->tv.margins.top != new_conn_state->tv.margins.top ||
old_conn_state->tv.margins.bottom != new_conn_state->tv.margins.bottom ||
old_conn_state->tv.mode != new_conn_state->tv.mode ||
old_conn_state->tv.brightness != new_conn_state->tv.brightness ||
old_conn_state->tv.contrast != new_conn_state->tv.contrast ||
old_conn_state->tv.flicker_reduction != new_conn_state->tv.flicker_reduction ||
old_conn_state->tv.overscan != new_conn_state->tv.overscan ||
old_conn_state->tv.saturation != new_conn_state->tv.saturation ||
old_conn_state->tv.hue != new_conn_state->tv.hue)
crtc_state->connectors_changed = true;
return 0;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state)
{
memcpy(state, connector->state, sizeof(*state));
if (state->crtc)
drm_connector_get(connector);
state->commit = NULL;
if (state->hdr_output_metadata)
drm_property_blob_get(state->hdr_output_metadata);
state->writeback_job = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
struct drm_connector_state *
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
{
struct drm_connector_state *state;
if (WARN_ON(!connector->state))
return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_connector_duplicate_state(connector, state);
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
void
__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
{
if (state->crtc)
drm_connector_put(state->connector);
if (state->commit)
drm_crtc_commit_put(state->commit);
if (state->writeback_job)
drm_writeback_cleanup_job(state->writeback_job);
drm_property_blob_put(state->hdr_output_metadata);
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state)
{
__drm_atomic_helper_connector_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
memcpy(state, obj->state, sizeof(*state));
}
EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
__drm_atomic_helper_private_obj_duplicate_state(&bridge->base,
&state->base);
state->bridge = bridge;
}
EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state);
struct drm_bridge_state *
drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge)
{
struct drm_bridge_state *new;
if (WARN_ON(!bridge->base.state))
return NULL;
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (new)
__drm_atomic_helper_bridge_duplicate_state(bridge, new);
return new;
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_duplicate_state);
void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
memset(state, 0, sizeof(*state));
state->bridge = bridge;
}
EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
struct drm_bridge_state *
drm_atomic_helper_bridge_reset(struct drm_bridge *bridge)
{
struct drm_bridge_state *bridge_state;
bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL);
if (!bridge_state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_bridge_reset(bridge, bridge_state);
return bridge_state;
}
EXPORT_SYMBOL