blob: 7c7c7dc8bf956f6b72a32df31e984aa60cc7191b [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_crtc.h"
#include "exynos_drm_dpp.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_format.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_decon.h"
static struct drm_plane_state *
exynos_drm_plane_duplicate_state(struct drm_plane *plane)
{
struct exynos_drm_plane_state *exynos_state;
struct exynos_drm_plane_state *copy;
exynos_state = to_exynos_plane_state(plane->state);
copy = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
if (!copy)
return NULL;
memcpy(copy, exynos_state, sizeof(*exynos_state));
if (copy->eotf_lut)
drm_property_blob_get(copy->eotf_lut);
if (copy->oetf_lut)
drm_property_blob_get(copy->oetf_lut);
if (copy->gm)
drm_property_blob_get(copy->gm);
if (copy->tm)
drm_property_blob_get(copy->tm);
__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
return &copy->base;
}
static void exynos_drm_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct exynos_drm_plane_state *old_exynos_state =
to_exynos_plane_state(old_state);
drm_property_blob_put(old_exynos_state->eotf_lut);
drm_property_blob_put(old_exynos_state->oetf_lut);
drm_property_blob_put(old_exynos_state->gm);
drm_property_blob_put(old_exynos_state->tm);
__drm_atomic_helper_plane_destroy_state(old_state);
kfree(old_exynos_state);
}
static void exynos_drm_plane_reset(struct drm_plane *plane)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_plane_state *exynos_state;
if (plane->state) {
exynos_drm_plane_destroy_state(plane, plane->state);
plane->state = NULL;
}
exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
if (exynos_state) {
plane->state = &exynos_state->base;
plane->state->plane = plane;
plane->state->zpos = exynos_plane->index;
plane->state->normalized_zpos = exynos_plane->index;
plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
plane->state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
}
}
static int
exynos_drm_replace_property_blob_from_id(struct drm_device *dev,
struct drm_property_blob **blob,
uint64_t blob_id,
ssize_t expected_size)
{
struct drm_property_blob *new_blob = NULL;
if (blob_id != 0) {
new_blob = drm_property_lookup_blob(dev, blob_id);
if (!new_blob)
return -EINVAL;
if (new_blob->length != expected_size) {
drm_property_blob_put(new_blob);
return -EINVAL;
}
}
drm_property_replace_blob(blob, new_blob);
drm_property_blob_put(new_blob);
return 0;
}
static int exynos_drm_plane_set_property(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
uint64_t val)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_plane_state *exynos_state =
to_exynos_plane_state(state);
int ret = 0;
if (property == exynos_plane->props.max_luminance) {
exynos_state->max_luminance = val;
} else if (property == exynos_plane->props.min_luminance) {
exynos_state->min_luminance = val;
} else if (property == exynos_plane->props.standard) {
exynos_state->standard = val;
} else if (property == exynos_plane->props.transfer) {
exynos_state->transfer = val;
} else if (property == exynos_plane->props.range) {
exynos_state->range = val;
} else if (property == exynos_plane->props.colormap) {
exynos_state->colormap = val;
} else if (property == exynos_plane->props.eotf_lut) {
ret = exynos_drm_replace_property_blob_from_id(
state->plane->dev, &exynos_state->eotf_lut,
val, sizeof(struct hdr_eotf_lut));
} else if (property == exynos_plane->props.oetf_lut) {
ret = exynos_drm_replace_property_blob_from_id(
state->plane->dev, &exynos_state->oetf_lut,
val, sizeof(struct hdr_oetf_lut));
} else if (property == exynos_plane->props.gm) {
ret = exynos_drm_replace_property_blob_from_id(
state->plane->dev, &exynos_state->gm,
val, sizeof(struct hdr_gm_data));
} else if (property == exynos_plane->props.tm) {
ret = exynos_drm_replace_property_blob_from_id(
state->plane->dev, &exynos_state->tm,
val, sizeof(struct hdr_tm_data));
} else {
return -EINVAL;
}
return ret;
}
static int exynos_drm_plane_get_property(struct drm_plane *plane,
const struct drm_plane_state *state,
struct drm_property *property,
uint64_t *val)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_plane_state *exynos_state =
to_exynos_plane_state((struct drm_plane_state *)state);
if (property == exynos_plane->props.restriction)
*val = exynos_state->blob_id_restriction;
else if (property == exynos_plane->props.max_luminance)
*val = exynos_state->max_luminance;
else if (property == exynos_plane->props.min_luminance)
*val = exynos_state->min_luminance;
else if (property == exynos_plane->props.standard)
*val = exynos_state->standard;
else if (property == exynos_plane->props.transfer)
*val = exynos_state->transfer;
else if (property == exynos_plane->props.range)
*val = exynos_state->range;
else if (property == exynos_plane->props.colormap)
*val = exynos_state->colormap;
else if (property == exynos_plane->props.eotf_lut)
*val = (exynos_state->eotf_lut) ?
exynos_state->eotf_lut->base.id : 0;
else if (property == exynos_plane->props.oetf_lut)
*val = (exynos_state->oetf_lut) ?
exynos_state->oetf_lut->base.id : 0;
else if (property == exynos_plane->props.gm)
*val = (exynos_state->gm) ? exynos_state->gm->base.id : 0;
else if (property == exynos_plane->props.tm)
*val = (exynos_state->tm) ? exynos_state->tm->base.id : 0;
else
return -EINVAL;
return 0;
}
static void exynos_drm_plane_print_state(struct drm_printer *p,
const struct drm_plane_state *state)
{
struct exynos_drm_plane_state *exynos_state =
to_exynos_plane_state(state);
struct exynos_drm_plane *exynos_plane = to_exynos_plane(state->plane);
struct dpp_device *dpp = plane_to_dpp(exynos_plane);
drm_printf(p, "\talpha: 0x%x\n", state->alpha);
drm_printf(p, "\tluminance: min=%d max=%d\n",
exynos_state->min_luminance, exynos_state->max_luminance);
drm_printf(p, "\tDPP #%d", dpp->id);
if (dpp->state == DPP_STATE_OFF) {
drm_printf(p, " (off)\n");
} else {
drm_printf(p, "\n\t\tdecon_id=%d\n", dpp->decon_id);
if (dpp->is_win_connected)
drm_printf(p, "\t\twin_id=%d\n", dpp->win_id);
}
}
static int exynos_drm_plane_late_register(struct drm_plane *plane)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
return exynos_drm_debugfs_plane_add(exynos_plane);
}
static struct drm_plane_funcs exynos_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
.reset = exynos_drm_plane_reset,
.atomic_duplicate_state = exynos_drm_plane_duplicate_state,
.atomic_destroy_state = exynos_drm_plane_destroy_state,
.atomic_set_property = exynos_drm_plane_set_property,
.atomic_get_property = exynos_drm_plane_get_property,
.atomic_print_state = exynos_drm_plane_print_state,
.late_register = exynos_drm_plane_late_register,
};
static int
exynos_drm_plane_check_format(struct exynos_drm_plane_state *state)
{
struct drm_framebuffer *fb = state->base.fb;
if (!fb)
return 0;
if (fb->modifier) {
uint64_t modifier = fb->modifier;
if (has_all_bits(DRM_FORMAT_MOD_SAMSUNG_COLORMAP, modifier))
return 0;
/* allow rest of the modifiers to support content protection */
modifier &= ~DRM_FORMAT_MOD_PROTECTION;
if (!modifier ||
has_all_bits(DRM_FORMAT_MOD_ARM_AFBC(0), modifier) ||
has_all_bits(DRM_FORMAT_MOD_SAMSUNG_SBWC(0), modifier))
return 0;
DRM_ERROR("not supported modifier(0x%llx)\n", fb->modifier);
return -ENOTSUPP;
}
return 0;
}
static void
exynos_plane_update_hdr_params(struct exynos_drm_plane_state *exynos_state)
{
struct exynos_hdr_state *hdr_state = &exynos_state->hdr_state;
struct hdr_eotf_lut *eotf_lut;
struct hdr_oetf_lut *oetf_lut;
struct hdr_gm_data *gm;
struct hdr_tm_data *tm;
if (exynos_state->eotf_lut) {
eotf_lut = (struct hdr_eotf_lut *)exynos_state->eotf_lut->data;
hdr_state->eotf_lut = eotf_lut;
} else {
hdr_state->eotf_lut = NULL;
}
if (exynos_state->oetf_lut) {
oetf_lut = (struct hdr_oetf_lut *)exynos_state->oetf_lut->data;
hdr_state->oetf_lut = oetf_lut;
} else {
hdr_state->oetf_lut = NULL;
}
if (exynos_state->gm) {
gm = (struct hdr_gm_data *)exynos_state->gm->data;
hdr_state->gm = gm;
} else {
hdr_state->gm = NULL;
}
if (exynos_state->tm) {
tm = (struct hdr_tm_data *)exynos_state->tm->data;
hdr_state->tm = tm;
} else {
hdr_state->tm = NULL;
}
}
static int exynos_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_plane_state *exynos_state =
to_exynos_plane_state(state);
struct dpp_device *dpp = plane_to_dpp(exynos_plane);
struct drm_crtc_state *new_crtc_state;
struct exynos_drm_crtc_state *new_exynos_crtc_state;
struct decon_device *decon;
int ret = 0;
DRM_DEBUG("%s +\n", __func__);
if (!state->crtc || !state->fb)
return 0;
decon = to_exynos_crtc(state->crtc)->ctx;
new_crtc_state = drm_atomic_get_new_crtc_state(state->state,
state->crtc);
if (!new_crtc_state->active)
return 0;
new_exynos_crtc_state = to_exynos_crtc_state(new_crtc_state);
/*
* while exiting hibernation, there's no point on running remaining checks
*/
if (new_exynos_crtc_state->hibernation_exit)
return 0;
ret = drm_atomic_helper_check_plane_state(state, new_crtc_state, 0,
INT_MAX, true, false);
if (ret)
return ret;
if (decon->partial && new_exynos_crtc_state->needs_reconfigure)
exynos_partial_reconfig_coords(decon->partial, state,
&new_exynos_crtc_state->partial_region);
exynos_plane_update_hdr_params(exynos_state);
if (dpp->check && state->visible) {
ret = dpp->check(dpp, exynos_state);
if (ret)
return ret;
}
ret = exynos_drm_plane_check_format(exynos_state);
if (ret)
return ret;
DRM_DEBUG("%s -\n", __func__);
return ret;
}
static void exynos_plane_disable(struct drm_plane *plane, struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
if (exynos_crtc->ops->disable_plane)
exynos_crtc->ops->disable_plane(exynos_crtc, exynos_plane);
}
static void exynos_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = plane->state;
struct exynos_drm_crtc *exynos_crtc;
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
if (!state->crtc)
return;
exynos_crtc = to_exynos_crtc(state->crtc);
if (!state->visible)
exynos_plane_disable(plane, state->crtc);
else if (exynos_crtc->ops->update_plane)
exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
}
static void exynos_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
if (!old_state || !old_state->crtc)
return;
exynos_plane_disable(plane, old_state->crtc);
}
static int exynos_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
struct decon_device *decon;
if (!new_state || !new_state->crtc) {
/* Do nothing because we only record event log on decon level */
return 0;
}
decon = crtc_to_decon(new_state->crtc);
DPU_EVENT_LOG(DPU_EVT_PLANE_PREPARE_FB, decon->id, new_state);
return 0;
}
static void exynos_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct decon_device *decon;
if (!old_state || !old_state->crtc)
return;
decon = crtc_to_decon(old_state->crtc);
DPU_EVENT_LOG(DPU_EVT_PLANE_CLEANUP_FB, decon->id, old_state);
}
static const struct drm_plane_helper_funcs plane_helper_funcs = {
.prepare_fb = exynos_plane_prepare_fb,
.cleanup_fb = exynos_plane_cleanup_fb,
.atomic_check = exynos_plane_atomic_check,
.atomic_update = exynos_plane_atomic_update,
.atomic_disable = exynos_plane_atomic_disable,
};
static int exynos_drm_plane_create_restriction_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property_blob *blob;
struct drm_property *prop;
struct dpp_ch_restriction res;
const struct dpp_device *dpp = plane_to_dpp(exynos_plane);
memcpy(&res.restriction, &dpp->restriction,
sizeof(struct dpp_restriction));
res.id = dpp->id;
res.attr = dpp->attr;
blob = drm_property_create_blob(plane->dev, sizeof(res), &res);
if (IS_ERR(blob))
return PTR_ERR(blob);
prop = drm_property_create(plane->dev,
DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
"hw restrictions", 0);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, blob->base.id);
exynos_plane->props.restriction = prop;
return 0;
}
static int exynos_drm_plane_create_standard_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
static const struct drm_prop_enum_list standard_list[] = {
{ EXYNOS_STANDARD_UNSPECIFIED, "Unspecified" },
{ EXYNOS_STANDARD_BT709, "BT709" },
{ EXYNOS_STANDARD_BT601_625, "BT601_625" },
{ EXYNOS_STANDARD_BT601_625_UNADJUSTED, "BT601_625_UNADJUSTED"},
{ EXYNOS_STANDARD_BT601_525, "BT601_525" },
{ EXYNOS_STANDARD_BT601_525_UNADJUSTED, "BT601_525_UNADJUSTED"},
{ EXYNOS_STANDARD_BT2020, "BT2020" },
{ EXYNOS_STANDARD_BT2020_CONSTANT_LUMINANCE,
"BT2020_CONSTANT_LUMINANCE"},
{ EXYNOS_STANDARD_BT470M, "BT470M" },
{ EXYNOS_STANDARD_FILM, "FILM" },
{ EXYNOS_STANDARD_DCI_P3, "DCI-P3" },
{ EXYNOS_STANDARD_ADOBE_RGB, "Adobe RGB" },
};
prop = drm_property_create_enum(plane->dev, 0, "standard",
standard_list, ARRAY_SIZE(standard_list));
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop,
EXYNOS_STANDARD_UNSPECIFIED);
exynos_plane->props.standard = prop;
return 0;
}
static int exynos_drm_plane_create_transfer_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
static const struct drm_prop_enum_list transfer_list[] = {
{ EXYNOS_TRANSFER_UNSPECIFIED, "Unspecified" },
{ EXYNOS_TRANSFER_LINEAR, "Linear" },
{ EXYNOS_TRANSFER_SRGB, "sRGB" },
{ EXYNOS_TRANSFER_SMPTE_170M, "SMPTE 170M" },
{ EXYNOS_TRANSFER_GAMMA2_2, "Gamma 2.2" },
{ EXYNOS_TRANSFER_GAMMA2_6, "Gamma 2.6" },
{ EXYNOS_TRANSFER_GAMMA2_8, "Gamma 2.8" },
{ EXYNOS_TRANSFER_ST2084, "ST2084" },
{ EXYNOS_TRANSFER_HLG, "HLG" },
};
prop = drm_property_create_enum(plane->dev, 0, "transfer",
transfer_list, ARRAY_SIZE(transfer_list));
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop,
EXYNOS_TRANSFER_UNSPECIFIED);
exynos_plane->props.transfer = prop;
return 0;
}
static int exynos_drm_plane_create_range_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
static const struct drm_prop_enum_list range_list[] = {
{ EXYNOS_RANGE_UNSPECIFIED, "Unspecified" },
{ EXYNOS_RANGE_FULL, "Full" },
{ EXYNOS_RANGE_LIMITED, "Limited" },
{ EXYNOS_RANGE_EXTENDED, "Extended" },
};
prop = drm_property_create_enum(plane->dev, 0, "range", range_list,
ARRAY_SIZE(range_list));
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop,
EXYNOS_RANGE_UNSPECIFIED);
exynos_plane->props.range = prop;
return 0;
}
static int exynos_drm_plane_create_colormap_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
prop = drm_property_create_range(plane->dev, 0, "colormap", 0,
UINT_MAX);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.colormap = prop;
return 0;
}
static int exynos_drm_plane_create_max_luminance_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
prop = drm_property_create_range(plane->dev, 0, "max_luminance", 0,
UINT_MAX);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.max_luminance = prop;
return 0;
}
static int exynos_drm_plane_create_min_luminance_property(
struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_property *prop;
prop = drm_property_create_range(plane->dev, 0, "min_luminance", 0,
UINT_MAX);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.min_luminance = prop;
return 0;
}
static int
exynos_drm_plane_create_eotf_lut_property(struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_device *dev = plane->dev;
struct drm_property *prop;
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "eotf_lut", 0);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.eotf_lut = prop;
return 0;
}
static int
exynos_drm_plane_create_oetf_lut_property(struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_device *dev = plane->dev;
struct drm_property *prop;
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "oetf_lut", 0);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.oetf_lut = prop;
return 0;
}
static int
exynos_drm_plane_create_gm_property(struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_device *dev = plane->dev;
struct drm_property *prop;
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "gammut_matrix", 0);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.gm = prop;
return 0;
}
static int
exynos_drm_plane_create_tm_property(struct exynos_drm_plane *exynos_plane)
{
struct drm_plane *plane = &exynos_plane->base;
struct drm_device *dev = plane->dev;
struct drm_property *prop;
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "tone_mapping", 0);
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
exynos_plane->props.tm = prop;
return 0;
}
int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, unsigned int index,
const struct exynos_drm_plane_config *config)
{
int err;
struct dpp_device *dpp = plane_to_dpp(exynos_plane);
unsigned int supported_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE);
struct drm_plane *plane = &exynos_plane->base;
err = drm_universal_plane_init(dev, plane, 0, &exynos_plane_funcs,
config->pixel_formats,
config->num_pixel_formats,
NULL, config->type, NULL);
if (err) {
DRM_ERROR("failed to initialize plane\n");
return err;
}
drm_plane_helper_add(plane, &plane_helper_funcs);
exynos_plane->index = index;
if (!test_bit(DPP_ATTR_RCD, &dpp->attr)) {
drm_plane_create_alpha_property(plane);
drm_plane_create_blend_mode_property(plane, supported_modes);
drm_plane_create_zpos_property(plane, config->zpos, 0, MAX_PLANE - 1);
exynos_drm_plane_create_standard_property(exynos_plane);
exynos_drm_plane_create_transfer_property(exynos_plane);
exynos_drm_plane_create_range_property(exynos_plane);
exynos_drm_plane_create_colormap_property(exynos_plane);
} else {
drm_plane_create_zpos_immutable_property(plane, MAX_PLANE);
}
if (test_bit(DPP_ATTR_ROT, &dpp->attr))
drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
else if (test_bit(DPP_ATTR_FLIP, &dpp->attr))
drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
if (test_bit(DPP_ATTR_HDR, &dpp->attr)) {
exynos_drm_plane_create_max_luminance_property(exynos_plane);
exynos_drm_plane_create_min_luminance_property(exynos_plane);
exynos_drm_plane_create_eotf_lut_property(exynos_plane);
exynos_drm_plane_create_oetf_lut_property(exynos_plane);
exynos_drm_plane_create_gm_property(exynos_plane);
}
if (test_bit(DPP_ATTR_HDR10_PLUS, &dpp->attr))
exynos_drm_plane_create_tm_property(exynos_plane);
exynos_drm_plane_create_restriction_property(exynos_plane);
return 0;
}