@@ -7139,8 +7139,15 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
acrtc->otg_inst = -1;
dm->adev->mode_info.crtcs[crtc_index] = acrtc;
- drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
- true, MAX_COLOR_LUT_ENTRIES);
+
+ res = drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
+ true, MAX_COLOR_LUT_ENTRIES,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (res) {
+ drm_crtc_cleanup(&acrtc->base);
+ goto fail;
+ }
+
drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
return 0;
@@ -626,7 +626,12 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms,
crtc->port = kcrtc->master->of_output_port;
- drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE);
+ err = drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (err) {
+ drm_crtc_cleanup(crtc);
+ return err;
+ }
return err;
}
@@ -552,7 +552,12 @@ int malidp_crtc_init(struct drm_device *drm)
drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE);
/* No inverse-gamma: it is per-plane. */
- drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE);
+ ret = drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ drm_crtc_cleanup(&malidp->crtc);
+ return ret;
+ }
malidp_se_set_enh_coeffs(malidp->dev);
@@ -992,7 +992,10 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
if (ret)
return ret;
- drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256);
+ ret = drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, ,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret)
+ return ret;
return armada_overlay_plane_create(drm, 1 << dcrtc->num);
@@ -528,8 +528,11 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
drm_mode_crtc_set_gamma_size(&crtc->base, ATMEL_HLCDC_CLUT_SIZE);
- drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
- ATMEL_HLCDC_CLUT_SIZE);
+ ret = drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
+ ATMEL_HLCDC_CLUT_SIZE,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret)
+ goto fail;
dc->crtc = &crtc->base;
@@ -147,12 +147,21 @@ u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n)
}
EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n);
+static const char * const tf_name[] = {
+ [DRM_TF_UNDEFINED] = "undefined",
+ [DRM_TF_SRGB] = "sRGB",
+ [DRM_TF_PQ2084] = "PQ2084",
+ [DRM_TF_1D_LUT] = "1D LUT",
+};
+
/**
* drm_crtc_enable_color_mgmt - enable color management properties
* @crtc: DRM CRTC
* @degamma_lut_size: the size of the degamma lut (before CSC)
* @has_ctm: whether to attach ctm_property for CSC matrix
* @gamma_lut_size: the size of the gamma lut (after CSC)
+ * @supported_tfs: bitfield indicating supported transfer functions
+ * @default_tf: default output transfer function
*
* This function lets the driver enable the color correction
* properties on a CRTC. This includes 3 degamma, csc and gamma
@@ -162,13 +171,27 @@ EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n);
* their size is not 0 and ctm_property is only attached if has_ctm is
* true.
*/
-void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+bool drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
uint degamma_lut_size,
bool has_ctm,
- uint gamma_lut_size)
+ uint gamma_lut_size,
+ u32 supported_tfs,
+ enum drm_transfer_function default_tf)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
+ struct drm_property *prop;
+ struct drm_prop_enum_list enum_list[DRM_TF_MAX];
+ int i, len;
+
+ if (WARN_ON(supported_tfs == 0 ||
+ (supported_tfs & -BIT(DRM_TF_MAX)) != 0 ||
+ (supported_tfs & BIT(default_tf)) == 0))
+ return -EINVAL;
+
+ if (!!(supported_tfs & BIT(DRM_TF_1D_LUT)) !=
+ !!(degamma_lut_size || gamma_lut_size))
+ return -EINVAL;
if (degamma_lut_size) {
drm_object_attach_property(&crtc->base,
@@ -189,6 +212,28 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
config->gamma_lut_size_property,
gamma_lut_size);
}
+
+ len = 0;
+ for (i = 0; i < DRM_TF_MAX; i++) {
+ if ((supported_tfs & BIT(i)) == 0)
+ continue;
+
+ enum_list[len].type = i;
+ enum_list[len].name = tf_name[i];
+ len++;
+ }
+
+ prop = drm_property_create_enum(dev, 0, "OUT TRANSFER_FUNCTION",
+ enum_list, len);
+ if (!prop)
+ return -ENOMEM;
+ crtc->out_transfer_function_property = prop;
+ drm_object_attach_property(&crtc->base, prop, default_tf);
+ if (crtc->state)
+ crtc->state->out_transfer_function = default_tf;
+
+ return 0;
+
}
EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
@@ -481,11 +526,6 @@ static const char * const color_range_name[] = {
[DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
};
-static const char * const tf_name[] = {
- [DRM_TF_UNDEFINED] = "undefined",
- [DRM_TF_SRGB] = "sRGB",
- [DRM_TF_PQ2084] = "PQ2084",
-};
/**
* drm_get_color_encoding_name - return a string for color encoding
* @encoding: color encoding to compute name of
@@ -2092,7 +2092,7 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
}
}
-void intel_color_init(struct intel_crtc *crtc)
+bool intel_color_init(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
bool has_ctm = INTEL_INFO(dev_priv)->color.degamma_lut_size != 0;
@@ -2149,8 +2149,9 @@ void intel_color_init(struct intel_crtc *crtc)
}
}
- drm_crtc_enable_color_mgmt(&crtc->base,
- INTEL_INFO(dev_priv)->color.degamma_lut_size,
- has_ctm,
- INTEL_INFO(dev_priv)->color.gamma_lut_size);
+ return drm_crtc_enable_color_mgmt(&crtc->base,
+ INTEL_INFO(dev_priv)->color.degamma_lut_size,
+ has_ctm,
+ INTEL_INFO(dev_priv)->color.gamma_lut_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
}
@@ -12,7 +12,7 @@ struct intel_crtc_state;
struct intel_crtc;
struct drm_property_blob;
-void intel_color_init(struct intel_crtc *crtc);
+bool intel_color_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state);
void intel_color_commit(const struct intel_crtc_state *crtc_state);
void intel_color_load_luts(const struct intel_crtc_state *crtc_state);
@@ -340,7 +340,9 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
- intel_color_init(crtc);
+ ret = intel_color_init(crtc);
+ if (ret)
+ goto fail;
intel_crtc_crc_init(crtc);
@@ -971,8 +971,13 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
return ret;
}
- drm_crtc_enable_color_mgmt(&priv->crtc, 0, false,
- ARRAY_SIZE(priv->dma_hwdescs->palette));
+ ret = drm_crtc_enable_color_mgmt(&priv->crtc, 0, false,
+ ARRAY_SIZE(priv->dma_hwdescs->palette),
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ dev_err(dev, "Failed to init color management: %i\n", ret);
+ return ret;
+ }
if (soc_info->has_osd) {
drm_plane_helper_add(&priv->f0,
@@ -827,7 +827,13 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
if (gamma_lut_size)
drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size);
- drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size);
+ ret = drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ drm_crtc_cleanup(mtk_crtc->base);
+ kfree(mtk_crtc);
+ return ret;
+
priv->num_pipes++;
mutex_init(&mtk_crtc->hw_lock);
@@ -1340,6 +1340,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
int i;
+ int ret = 0;
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1368,7 +1369,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs);
- drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, true, 0,
+ BIT(DRM_TF_UNDEFINED), DRM_TF_UNDEFINED);
+ if (ret) {
+ drm_crtc_cleanup(crtc);
+ kfree(dpu_crtc);
+ return ERR_PTR(ret);
+ }
/* save user friendly CRTC name for later */
snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id);
@@ -589,9 +589,16 @@ nv50_head_create(struct drm_device *dev, int index)
drm_crtc_helper_add(crtc, &nv50_head_help);
/* Keep the legacy gamma size at 256 to avoid compatibility issues */
drm_mode_crtc_set_gamma_size(crtc, 256);
- drm_crtc_enable_color_mgmt(crtc, base->func->ilut_size,
- disp->disp->object.oclass >= GF110_DISP,
- head->func->olut_size);
+ ret = drm_crtc_enable_color_mgmt(crtc, base->func->ilut_size,
+ disp->disp->object.oclass >= GF110_DISP,
+ head->func->olut_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ drm_crtc_cleanup(crtc);
+ kfree(head);
+ return ERR_PTR(ret);
+ }
+
if (head->func->olut_set) {
ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut);
@@ -839,7 +839,15 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
if (dispc_mgr_gamma_size(priv->dispc, channel)) {
unsigned int gamma_lut_size = 256;
- drm_crtc_enable_color_mgmt(crtc, gamma_lut_size, true, 0);
+ ret = drm_crtc_enable_color_mgmt(crtc, gamma_lut_size, true, 0,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ dev_err(dev->dev, "$s(): could not init color management for: %s\n",
+ __func__, pipe->output->name);
+ drm_crtc_cleanup(crtc);
+ kfree(omap_crtc);
+ return ERR_PTR(ret);
+ }
drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
}
@@ -1263,7 +1263,12 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
rgrp->cmms_mask |= BIT(hwindex % 2);
drm_mode_crtc_set_gamma_size(crtc, CM2_LUT_SIZE);
- drm_crtc_enable_color_mgmt(crtc, 0, false, CM2_LUT_SIZE);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, false, CM2_LUT_SIZE,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ drm_crtc_cleanup(crtc);
+ return ret;
+ }
}
drm_crtc_helper_add(crtc, &crtc_helper_funcs);
@@ -1816,7 +1816,10 @@ static int vop_create_crtc(struct vop *vop)
drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
if (vop->lut_regs) {
drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size);
- drm_crtc_enable_color_mgmt(crtc, 0, false, vop_data->lut_size);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, false, vop_data->lut_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret)
+ goto err_cleanup_crtc;
}
/*
@@ -1034,7 +1034,13 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs);
drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE);
- drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ DRM_ERROR("Can not initialize color management\n");
+ drm_crtc_cleanup(crtc);
+ goto cleanup;
+ }
DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id);
@@ -439,7 +439,14 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
if (tidss->feat->vp_feat.color.gamma_size)
gamma_lut_size = 256;
- drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ drm_crtc_cleanup(crtc);
+ kfree(tcrtc);
+ return ERR_PTR(ret);
+ }
+
if (gamma_lut_size)
drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
@@ -1074,12 +1074,24 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
if (!vc4->hvs->hvs5) {
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
- drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ dev_err(drm->dev, "failed to enable color management\n");
+ drm_crtc_cleanup(crtc);
+ return ret;
+ }
/* We support CTM, but only for one CRTC at a time. It's therefore
* implemented as private driver state in vc4_kms, not here.
*/
- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
+ ret = drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size,
+ BIT(DRM_TF_1D_LUT), DRM_TF_1D_LUT);
+ if (ret) {
+ dev_err(drm->dev, "failed to enable color management\n");
+ drm_crtc_cleanup(crtc);
+ return ret;
+ }
}
for (i = 0; i < crtc->gamma_size; i++) {
@@ -54,10 +54,29 @@ static inline u32 drm_color_lut_extract(u32 user_input, int bit_precision)
u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n);
-void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+/**
+ * enum drm_transfer_function - common transfer function used for sdr/hdr formats
+ *
+ * DRM_TF_UNDEFINED - The legacy case where a TF in and out of the blending
+ * space is undefined
+ * DRM_TF_SRGB - Based on gamma curve and is used for printer/monitors/web
+ * DRM_TF_PQ2084 - Used for HDR and allows for up to 10,000 nit support.
+ * DRM_TF_1D_LUT - Use 1D gamma/degamma LUTs (currently only defined on crtc)
+*/
+enum drm_transfer_function {
+ DRM_TF_UNDEFINED,
+ DRM_TF_SRGB,
+ DRM_TF_PQ2084,
+ DRM_TF_1D_LUT,
+ DRM_TF_MAX,
+};
+
+bool drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
uint degamma_lut_size,
bool has_ctm,
- uint gamma_lut_size);
+ uint gamma_lut_size,
+ u32 supported_tfs,
+ enum drm_transfer_function default_tf);
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size);
@@ -87,20 +106,6 @@ enum drm_color_range {
DRM_COLOR_RANGE_MAX,
};
-/**
- * enum drm_transfer_function - common transfer function used for sdr/hdr formats
- *
- * DRM_TF_UNDEFINED - The legacy case where a TF in and out of the blending
- * space is undefined
- * DRM_TF_SRGB - Based on gamma curve and is used for printer/monitors/web
- * DRM_TF_PQ2084 - Used for HDR and allows for up to 10,000 nit support.
-*/
-enum drm_transfer_function {
- DRM_TF_UNDEFINED,
- DRM_TF_SRGB,
- DRM_TF_PQ2084,
- DRM_TF_MAX,
-};
int drm_plane_create_color_properties(struct drm_plane *plane,
u32 supported_encodings,
u32 supported_ranges,
@@ -288,6 +288,15 @@ struct drm_crtc_state {
*/
struct drm_property_blob *gamma_lut;
+ /**
+ * @out_transfer_function:
+ *
+ * Transfer function for conversion from blending space to
+ * display space. DRM_TF_1D_LUT can be specified to use the
+ * gamma/degamma LUTs from mode_config instead.
+ */
+ enum drm_transfer_function out_transfer_function;
+
/**
* @target_vblank:
*
@@ -1096,6 +1105,17 @@ struct drm_crtc {
*/
struct drm_property *scaling_filter_property;
+ /**
+ * @out_transfer_function_property:
+ *
+ * Optional "OUT TRANSFER FUNCTION" enum property for specifying
+ * an output transfer function, i.e. a TF to convert from
+ * blending space to luminance space. Use DRM_TF_1D_LUT to
+ * indicate using the 1D gamma/degamma LUTs instead of a
+ * named transfer function.
+ */
+ struct drm_property *out_transfer_function_property;
+
/**
* @state:
*
We currently have 1D LUTs to define output transfer function but using a 1D LUT is not always the best way to define a transfer function for HW that has ROMs for certain transfer functions, or for HW that has complex PWL definition for accurate LUT definitions. For this reason we're introducing named transfer functions. The original LUT behavior is preserved with the default "1D LUT" transfer function. Signed-off-by: Harry Wentland <harry.wentland@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 +++- .../gpu/drm/arm/display/komeda/komeda_crtc.c | 7 ++- drivers/gpu/drm/arm/malidp_crtc.c | 7 ++- drivers/gpu/drm/armada/armada_crtc.c | 5 +- .../gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 7 ++- drivers/gpu/drm/drm_color_mgmt.c | 54 ++++++++++++++++--- drivers/gpu/drm/i915/display/intel_color.c | 11 ++-- drivers/gpu/drm/i915/display/intel_color.h | 2 +- drivers/gpu/drm/i915/display/intel_crtc.c | 4 +- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 9 +++- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 8 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 9 +++- drivers/gpu/drm/nouveau/dispnv50/head.c | 13 +++-- drivers/gpu/drm/omapdrm/omap_crtc.c | 10 +++- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 7 ++- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +- drivers/gpu/drm/stm/ltdc.c | 8 ++- drivers/gpu/drm/tidss/tidss_crtc.c | 9 +++- drivers/gpu/drm/vc4/vc4_crtc.c | 16 +++++- include/drm/drm_color_mgmt.h | 37 +++++++------ include/drm/drm_crtc.h | 20 +++++++ 21 files changed, 208 insertions(+), 51 deletions(-)