drm/msm: Add support for PCC in Crtc
CRTC contains the dspp block which contains color processing modules.
Change adds the pcc support to the CRTC.
Change-Id: Ib4091d43d819ab4f20f16892277ccd1d21285c61
Signed-off-by: Gopikrishnaiah Anandan <agopik@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 5c3dbd0..bb09c12 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -43,6 +43,7 @@
sde/sde_kms.o \
sde/sde_plane.o \
sde/sde_connector.o \
+ sde/sde_color_processing.o \
msm_atomic.o \
msm_debugfs.o \
msm_drv.o \
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 59efc45..453434d 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -281,6 +281,9 @@
struct drm_property *crtc_property[CRTC_PROP_COUNT];
struct drm_property *conn_property[CONNECTOR_PROP_COUNT];
+ /* Color processing properties for the crtc */
+ struct drm_property **cp_property;
+
/* VRAM carveout, used when no IOMMU: */
struct {
unsigned long size;
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index e5b7ad5..cce0cdf 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -350,7 +350,7 @@
property_idx = msm_property_index(info, property);
if (!info || (property_idx == -EINVAL) || !property_values) {
- DRM_ERROR("invalid argument(s)\n");
+ DRM_DEBUG("Invalid argument(s)\n");
} else {
/* extra handling for incoming properties */
mutex_lock(&info->property_lock);
@@ -399,7 +399,7 @@
property_idx = msm_property_index(info, property);
if (!info || (property_idx == -EINVAL) || !property_values || !val) {
- DRM_ERROR("invalid argument(s)\n");
+ DRM_DEBUG("Invalid argument(s)\n");
} else {
mutex_lock(&info->property_lock);
*val = property_values[property_idx];
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
new file mode 100644
index 0000000..a4dd81f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -0,0 +1,640 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <drm/msm_drm_pp.h>
+#include "sde_color_processing.h"
+#include "sde_kms.h"
+#include "sde_crtc.h"
+#include "sde_hw_dspp.h"
+#include "sde_hw_lm.h"
+
+struct sde_color_process_node {
+ u32 property_id;
+ u32 prop_flags;
+ u32 feature;
+ void *blob_ptr;
+ uint64_t prop_val;
+ const struct sde_pp_blk *pp_blk;
+ struct list_head feature_list;
+ struct list_head active_list;
+ struct list_head dirty_list;
+ void (*dspp_feature_op)(struct sde_hw_dspp *ctx, void *cfg);
+ void (*lm_feature_op)(struct sde_hw_mixer *mixer, void *cfg);
+};
+
+struct sde_cp_prop_attach {
+ struct drm_crtc *crtc;
+ struct drm_property *prop;
+ struct sde_color_process_node *prop_node;
+ const struct sde_pp_blk *pp_blk;
+ u32 feature;
+ void *ops;
+ uint64_t val;
+};
+
+enum {
+ /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
+ /* DSPP Features start */
+ SDE_CP_CRTC_DSPP_IGC,
+ SDE_CP_CRTC_DSPP_PCC,
+ SDE_CP_CRTC_DSPP_GC,
+ SDE_CP_CRTC_DSPP_HUE,
+ SDE_CP_CRTC_DSPP_SAT,
+ SDE_CP_CRTC_DSPP_VAL,
+ SDE_CP_CRTC_DSPP_CONT,
+ SDE_CP_CRTC_DSPP_MEMCOLOR,
+ SDE_CP_CRTC_DSPP_SIXZONE,
+ SDE_CP_CRTC_DSPP_GAMUT,
+ SDE_CP_CRTC_DSPP_DITHER,
+ SDE_CP_CRTC_DSPP_HIST,
+ SDE_CP_CRTC_DSPP_MAX,
+ /* DSPP features end */
+
+ /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
+ /* LM feature start*/
+ SDE_CP_CRTC_LM_GC,
+ /* LM feature end*/
+
+ SDE_CP_CRTC_MAX_FEATURES,
+};
+
+#define INIT_PROP_ATTACH(p, crtc, prop, node, blk, feature, ops, val) \
+ do { \
+ (p)->crtc = crtc; \
+ (p)->prop = prop; \
+ (p)->prop_node = node; \
+ (p)->pp_blk = blk; \
+ (p)->feature = feature; \
+ (p)->ops = ops; \
+ (p)->val = val; \
+ } while (0)
+
+static int sde_cp_disable_crtc_blob_property(
+ struct sde_color_process_node *prop_node)
+{
+ struct drm_property_blob *blob = prop_node->blob_ptr;
+
+ if (!blob)
+ return -EINVAL;
+ drm_property_unreference_blob(blob);
+ prop_node->blob_ptr = NULL;
+ return 0;
+}
+
+static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
+ struct drm_property *property,
+ struct sde_color_process_node *prop_node)
+{
+ int ret = 0;
+
+ if (property->flags & DRM_MODE_PROP_BLOB) {
+ ret = sde_cp_disable_crtc_blob_property(prop_node);
+ } else if (property->flags & DRM_MODE_PROP_RANGE) {
+ prop_node->prop_val = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
+ struct sde_color_process_node *prop_node,
+ uint64_t val)
+{
+ struct drm_property_blob *blob = NULL;
+
+ /**
+ * For non-blob based properties add support to create a blob
+ * using the val and store the blob_ptr in prop_node.
+ */
+ blob = drm_property_lookup_blob(crtc->dev, val);
+ if (!blob) {
+ DRM_ERROR("invalid blob id %lld\n", val);
+ return -EINVAL;
+ }
+ /* Release refernce to existing payload of the property */
+ if (prop_node->blob_ptr)
+ drm_property_unreference_blob(prop_node->blob_ptr);
+
+ prop_node->blob_ptr = blob;
+ return 0;
+}
+
+static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
+ struct drm_property *property,
+ struct sde_color_process_node *prop_node,
+ uint64_t val)
+{
+ int ret = -EINVAL;
+
+ if (property->flags & DRM_MODE_PROP_BLOB)
+ ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
+ else if (property->flags & DRM_MODE_PROP_RANGE) {
+ ret = 0;
+ prop_node->prop_val = val;
+ }
+ return ret;
+}
+
+static int sde_cp_crtc_get_mixer_idx(struct sde_crtc *sde_crtc)
+{
+ if (sde_crtc->num_mixers)
+ return sde_crtc->mixers[0].hw_lm->idx;
+ else
+ return -EINVAL;
+}
+
+static struct sde_kms *get_kms(struct drm_crtc *crtc)
+{
+ struct msm_drm_private *priv = crtc->dev->dev_private;
+
+ return to_sde_kms(priv->kms);
+}
+
+static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
+{
+
+ struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
+
+ drm_object_attach_property(&prop_attach->crtc->base,
+ prop_attach->prop, prop_attach->val);
+
+ INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
+ INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
+
+ prop_attach->prop_node->property_id = prop_attach->prop->base.id;
+ prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
+ prop_attach->prop_node->feature = prop_attach->feature;
+ prop_attach->prop_node->pp_blk = prop_attach->pp_blk;
+
+ if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
+ prop_attach->prop_node->dspp_feature_op = prop_attach->ops;
+ else
+ prop_attach->prop_node->lm_feature_op = prop_attach->ops;
+
+ list_add(&prop_attach->prop_node->feature_list,
+ &sde_crtc->feature_list);
+}
+
+void sde_cp_crtc_init(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc = NULL;
+
+ if (!crtc) {
+ DRM_ERROR("invalid crtc %pK\n", crtc);
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ INIT_LIST_HEAD(&sde_crtc->active_list);
+ INIT_LIST_HEAD(&sde_crtc->dirty_list);
+ INIT_LIST_HEAD(&sde_crtc->feature_list);
+}
+
+static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
+ char *name,
+ const struct sde_pp_blk *pp_blk,
+ u32 feature, void *ops,
+ uint64_t min, uint64_t max,
+ uint64_t val)
+{
+ struct drm_property *prop;
+ struct sde_color_process_node *prop_node = NULL;
+ struct msm_drm_private *priv;
+ struct sde_cp_prop_attach prop_attach;
+
+ if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
+ DRM_ERROR("invalid feature %d max %d\n", feature,
+ SDE_CP_CRTC_MAX_FEATURES);
+ return;
+ }
+
+ prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
+ if (!prop_node)
+ return;
+
+ priv = crtc->dev->dev_private;
+ prop = priv->cp_property[feature];
+
+ if (!prop) {
+ prop = drm_property_create_range(crtc->dev, 0, name, min, max);
+ if (!prop) {
+ DRM_ERROR("property create failed: %s\n", name);
+ kfree(prop_node);
+ return;
+ }
+ priv->cp_property[feature] = prop;
+ }
+
+ INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, pp_blk,
+ feature, ops, val);
+
+ sde_cp_crtc_prop_attach(&prop_attach);
+}
+
+static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
+ const struct sde_pp_blk *pp_blk,
+ u32 feature, void *ops)
+{
+ struct drm_property *prop;
+ struct sde_color_process_node *prop_node = NULL;
+ struct msm_drm_private *priv;
+ uint64_t val = 0;
+ struct sde_cp_prop_attach prop_attach;
+
+ if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
+ DRM_ERROR("invalid feature %d max %d\n", feature,
+ SDE_CP_CRTC_MAX_FEATURES);
+ return;
+ }
+
+ prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
+ if (!prop_node)
+ return;
+
+ priv = crtc->dev->dev_private;
+ prop = priv->cp_property[feature];
+
+ if (!prop) {
+ prop = drm_property_create(crtc->dev,
+ DRM_MODE_PROP_BLOB, name, 0);
+ if (!prop) {
+ DRM_ERROR("property create failed: %s\n", name);
+ kfree(prop_node);
+ return;
+ }
+ priv->cp_property[feature] = prop;
+ }
+
+ INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, pp_blk,
+ feature, ops, val);
+
+ sde_cp_crtc_prop_attach(&prop_attach);
+}
+
+
+static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
+ struct sde_crtc *sde_crtc)
+{
+ u32 num_mixers = sde_crtc->num_mixers;
+ uint64_t val = 0;
+ struct drm_property_blob *blob = NULL;
+ struct sde_hw_cp_cfg hw_cfg;
+ int i = 0;
+ bool is_dspp = true;
+
+ if (!prop_node->dspp_feature_op && !prop_node->lm_feature_op) {
+ DRM_ERROR("ops not set for dspp/lm\n");
+ return;
+ }
+
+ is_dspp = !prop_node->lm_feature_op;
+ memset(&hw_cfg, 0, sizeof(hw_cfg));
+ if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
+ blob = prop_node->blob_ptr;
+ if (blob) {
+ hw_cfg.len = blob->length;
+ hw_cfg.payload = blob->data;
+ }
+ } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
+ val = prop_node->prop_val;
+ hw_cfg.len = sizeof(prop_node->prop_val);
+ hw_cfg.payload = &prop_node->prop_val;
+ } else {
+ DRM_ERROR("property type is not supported\n");
+ return;
+ }
+
+ for (i = 0; i < num_mixers; i++) {
+ if (is_dspp) {
+ if (!sde_crtc->mixers[i].hw_dspp)
+ continue;
+ prop_node->dspp_feature_op(sde_crtc->mixers[i].hw_dspp,
+ &hw_cfg);
+ } else {
+ if (!sde_crtc->mixers[i].hw_lm)
+ continue;
+ prop_node->lm_feature_op(sde_crtc->mixers[i].hw_lm,
+ &hw_cfg);
+ }
+ }
+
+ if (blob || val) {
+ DRM_DEBUG_DRIVER("Add feature to active list %d\n",
+ prop_node->property_id);
+ list_add_tail(&prop_node->active_list, &sde_crtc->active_list);
+ } else {
+ DRM_DEBUG_DRIVER("remove feature from active list %d\n",
+ prop_node->property_id);
+ list_del_init(&prop_node->active_list);
+ }
+ /* Programming of feature done remove from dirty list */
+ list_del_init(&prop_node->dirty_list);
+}
+
+void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc = NULL;
+ bool set_dspp_flush = false, set_lm_flush = false;
+ struct sde_color_process_node *prop_node = NULL, *n = NULL;
+ struct sde_hw_ctl *ctl;
+ uint32_t flush_mask = 0;
+ u32 num_mixers = 0, i = 0;
+
+ if (!crtc || !crtc->dev) {
+ DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
+ (crtc ? crtc->dev : NULL));
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ num_mixers = sde_crtc->num_mixers;
+ if (!num_mixers) {
+ DRM_DEBUG_DRIVER("no mixers for this crtc\n");
+ return;
+ }
+
+ /* Check if dirty list is empty for early return */
+ if (list_empty(&sde_crtc->dirty_list)) {
+ DRM_DEBUG_DRIVER("Dirty list is empty\n");
+ return;
+ }
+
+ list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
+ dirty_list) {
+ sde_cp_crtc_setfeature(prop_node, sde_crtc);
+ /* Set the flush flag to true */
+ if (prop_node->dspp_feature_op)
+ set_dspp_flush = true;
+ else
+ set_lm_flush = true;
+ }
+
+ for (i = 0; i < num_mixers; i++) {
+ ctl = sde_crtc->mixers[i].hw_ctl;
+ if (!ctl)
+ continue;
+ if (set_dspp_flush && ctl->ops.get_bitmask_dspp
+ && sde_crtc->mixers[i].hw_dspp)
+ ctl->ops.get_bitmask_dspp(ctl,
+ &flush_mask,
+ sde_crtc->mixers[i].hw_dspp->idx);
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ if (set_lm_flush && ctl->ops.get_bitmask_mixer
+ && sde_crtc->mixers[i].hw_lm)
+ flush_mask = ctl->ops.get_bitmask_mixer(ctl,
+ sde_crtc->mixers[i].hw_lm->idx);
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ }
+}
+
+void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
+{
+ struct sde_kms *kms = NULL;
+ struct sde_crtc *sde_crtc = NULL;
+ struct sde_mdss_cfg *catalog = NULL;
+ unsigned long features = 0;
+ int idx = 0, i = 0;
+ char feature_name[256];
+ struct msm_drm_private *priv;
+ struct sde_hw_dspp *hw_dspp = NULL;
+ struct sde_hw_mixer *hw_mixer = NULL;
+
+ if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
+ DRM_ERROR("invalid crtc %pK dev %pK\n",
+ crtc, ((crtc) ? crtc->dev : NULL));
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ kms = get_kms(crtc);
+ if (!kms || !kms->catalog || !sde_crtc) {
+ DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
+ kms, ((kms) ? kms->catalog : NULL), sde_crtc);
+ return;
+ }
+
+ /**
+ * Function can be called during the atomic_check with test_only flag
+ * and actual commit. Allocate properties only if feature list is
+ * empty during the atomic_check with test_only flag.
+ */
+ if (!list_empty(&sde_crtc->feature_list))
+ return;
+
+ catalog = kms->catalog;
+ idx = sde_cp_crtc_get_mixer_idx(sde_crtc);
+ if (idx < 0 || idx >= catalog->mixer_count) {
+ DRM_ERROR("invalid idx %d\n", idx);
+ return;
+ }
+
+ priv = crtc->dev->dev_private;
+ /**
+ * DSPP/LM properties are global to all the CRTCS.
+ * Properties are created for first CRTC and re-used for later
+ * crtcs.
+ */
+ if (!priv->cp_property)
+ priv->cp_property = kzalloc((sizeof(priv->cp_property) *
+ SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
+ if (!priv->cp_property)
+ return;
+ memset(feature_name, 0, sizeof(feature_name));
+
+ if (idx >= catalog->dspp_count)
+ goto lm_property;
+
+ /* Check for all the DSPP properties and attach it to CRTC */
+ hw_dspp = sde_crtc->mixers[0].hw_dspp;
+ features = (hw_dspp) ? hw_dspp->cap->features : 0;
+
+ if (!hw_dspp || !hw_dspp->cap->sblk)
+ goto lm_property;
+
+ for (i = 0; i < SDE_DSPP_MAX; i++) {
+ if (!test_bit(i, &features))
+ continue;
+ switch (i) {
+ case SDE_DSPP_PCC:
+ snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+ "SDE_DSPP_PCC_V",
+ (hw_dspp->cap->sblk->pcc.version >> 16));
+ sde_cp_crtc_create_blob_property(crtc, feature_name,
+ &hw_dspp->cap->sblk->pcc,
+ SDE_CP_CRTC_DSPP_PCC,
+ hw_dspp->ops.setup_pcc);
+ break;
+ case SDE_DSPP_HSIC:
+ snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+ "SDE_DSPP_HUE_V",
+ (hw_dspp->cap->sblk->hsic.version >> 16));
+ sde_cp_crtc_install_range_property(crtc, feature_name,
+ &hw_dspp->cap->sblk->hsic,
+ SDE_CP_CRTC_DSPP_HUE, hw_dspp->ops.setup_hue,
+ 0, U32_MAX, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+lm_property:
+ /* Check for all the LM properties and attach it to CRTC */
+ hw_mixer = sde_crtc->mixers[0].hw_lm;
+ features = (hw_mixer) ? hw_mixer->cap->features : 0;
+
+ if (!hw_mixer || !hw_mixer->cap->sblk)
+ return;
+
+ for (i = 0; i < SDE_MIXER_MAX; i++) {
+ if (!test_bit(i, &features))
+ continue;
+ switch (i) {
+ case SDE_MIXER_GC:
+ snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+ "SDE_LM_GC_V",
+ (hw_mixer->cap->sblk->gc.version >> 16));
+ sde_cp_crtc_create_blob_property(crtc, feature_name,
+ &hw_mixer->cap->sblk->gc,
+ SDE_CP_CRTC_LM_GC,
+ hw_mixer->ops.setup_gc);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int sde_cp_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct sde_color_process_node *prop_node = NULL;
+ struct sde_crtc *sde_crtc = NULL;
+ int ret = 0;
+ u8 found = 0;
+
+ if (!crtc || !property) {
+ DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
+ return -EINVAL;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
+ if (property->base.id == prop_node->property_id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ /* remove the property from dirty list */
+ list_del_init(&prop_node->dirty_list);
+
+ if (!val)
+ ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
+ else
+ ret = sde_cp_enable_crtc_property(crtc, property,
+ prop_node, val);
+
+ if (!ret) {
+ /* remove the property from active list */
+ list_del_init(&prop_node->active_list);
+ /* Mark the feature as dirty */
+ list_add_tail(&prop_node->dirty_list, &sde_crtc->dirty_list);
+ }
+ return ret;
+}
+
+int sde_cp_crtc_get_property(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t *val)
+{
+ struct sde_color_process_node *prop_node = NULL;
+ struct sde_crtc *sde_crtc = NULL;
+ int ret = -EINVAL;
+
+ if (!crtc || !property || !val) {
+ DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
+ crtc, property, val);
+ return -EINVAL;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
+ if (property->base.id == prop_node->property_id) {
+ *val = prop_node->prop_val;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc = NULL;
+ struct sde_color_process_node *prop_node = NULL, *n = NULL;
+
+ if (!crtc) {
+ DRM_ERROR("invalid crtc %pK\n", crtc);
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
+ feature_list) {
+ if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
+ && prop_node->blob_ptr)
+ drm_property_unreference_blob(prop_node->blob_ptr);
+
+ list_del_init(&prop_node->active_list);
+ list_del_init(&prop_node->dirty_list);
+ list_del_init(&prop_node->feature_list);
+ kfree(prop_node);
+ }
+
+ INIT_LIST_HEAD(&sde_crtc->active_list);
+ INIT_LIST_HEAD(&sde_crtc->dirty_list);
+ INIT_LIST_HEAD(&sde_crtc->feature_list);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.h b/drivers/gpu/drm/msm/sde/sde_color_processing.h
new file mode 100644
index 0000000..2d62eae
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.h
@@ -0,0 +1,72 @@
+
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SDE_COLOR_PROCESSING_H
+#define _SDE_COLOR_PROCESSING_H
+#include <drm/drm_crtc.h>
+
+/**
+ * sde_cp_crtc_init(): Initialize color processing lists for a crtc.
+ * Should be called during crtc initialization.
+ * @crtc: Pointer to sde_crtc.
+ */
+void sde_cp_crtc_init(struct drm_crtc *crtc);
+
+/**
+ * sde_cp_crtc_install_properties(): Installs the color processing
+ * properties for a crtc.
+ * Should be called during crtc initialization.
+ * @crtc: Pointer to crtc.
+ */
+void sde_cp_crtc_install_properties(struct drm_crtc *crtc);
+
+/**
+ * sde_cp_crtc_destroy_properties: Destroys color processing
+ * properties for a crtc.
+ * should be called during crtc de-initialization.
+ * @crtc: Pointer to crtc.
+ */
+void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc);
+
+/**
+ * sde_cp_crtc_set_property: Set a color processing property
+ * for a crtc.
+ * Should be during atomic set property.
+ * @crtc: Pointer to crtc.
+ * @property: Property that needs to enabled/disabled.
+ * @val: Value of property.
+ */
+int sde_cp_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t val);
+
+/**
+ * sde_cp_crtc_apply_properties: Enable/disable properties
+ * for a crtc.
+ * Should be called during atomic commit call.
+ * @crtc: Pointer to crtc.
+ */
+void sde_cp_crtc_apply_properties(struct drm_crtc *crtc);
+
+/**
+ * sde_cp_crtc_get_property: Get value of color processing property
+ * for a crtc.
+ * Should be during atomic get property.
+ * @crtc: Pointer to crtc.
+ * @property: Property that needs to enabled/disabled.
+ * @val: Value of property.
+ *
+ */
+int sde_cp_crtc_get_property(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t *val);
+#endif /*_SDE_COLOR_PROCESSING_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 5615885..84aeb46 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include "sde_hw_lm.h"
#include "sde_hw_ctl.h"
#include "sde_crtc.h"
+#include "sde_color_processing.h"
#define CTL(i) (CTL_0 + (i))
#define LM(i) (LM_0 + (i))
@@ -64,6 +65,7 @@
return;
msm_property_destroy(&sde_crtc->property_info);
+ sde_cp_crtc_destroy_properties(crtc);
debugfs_remove_recursive(sde_crtc->debugfs_root);
sde_fence_deinit(&sde_crtc->output_fence);
@@ -495,10 +497,11 @@
struct sde_crtc_mixer *mixer;
struct sde_hw_ctl *last_valid_ctl = NULL;
int i;
- struct sde_rm_hw_iter lm_iter, ctl_iter;
+ struct sde_rm_hw_iter lm_iter, ctl_iter, dspp_iter;
sde_rm_init_hw_iter(&lm_iter, enc->base.id, SDE_HW_BLK_LM);
sde_rm_init_hw_iter(&ctl_iter, enc->base.id, SDE_HW_BLK_CTL);
+ sde_rm_init_hw_iter(&dspp_iter, enc->base.id, SDE_HW_BLK_DSPP);
/* Set up all the mixers and ctls reserved by this encoder */
for (i = sde_crtc->num_mixers; i < ARRAY_SIZE(sde_crtc->mixers); i++) {
@@ -525,6 +528,10 @@
return;
}
+ /* Dspp may be null */
+ (void) sde_rm_get_hw(rm, &dspp_iter);
+ mixer->hw_dspp = (struct sde_hw_dspp *)dspp_iter.hw;
+
mixer->encoder = enc;
sde_crtc->num_mixers++;
@@ -598,6 +605,7 @@
return;
_sde_crtc_blend_setup(crtc);
+ sde_cp_crtc_apply_properties(crtc);
/*
* PP_DONE irq is only used by command mode for now.
@@ -1026,7 +1034,12 @@
property);
if (idx == CRTC_PROP_INPUT_FENCE_TIMEOUT)
_sde_crtc_set_input_fence_timeout(cstate);
+ } else {
+ ret = sde_cp_crtc_set_property(crtc,
+ property, val);
}
+ if (ret)
+ DRM_ERROR("failed to set the property\n");
}
return ret;
@@ -1082,9 +1095,13 @@
ret = msm_property_atomic_get(&sde_crtc->property_info,
cstate->property_values,
cstate->property_blobs, property, val);
+ if (ret)
+ ret = sde_cp_crtc_get_property(crtc,
+ property, val);
}
+ if (ret)
+ DRM_ERROR("get property failed\n");
}
-
return ret;
}
@@ -1194,6 +1211,7 @@
return ERR_PTR(-ENOMEM);
crtc = &sde_crtc->base;
+ crtc->dev = dev;
sde_crtc->drm_crtc_id = drm_crtc_id;
atomic_set(&sde_crtc->drm_requested_vblank, 0);
@@ -1219,6 +1237,7 @@
sizeof(struct sde_crtc_state));
sde_crtc_install_properties(crtc);
+ sde_cp_crtc_init(crtc);
SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name);
return crtc;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index cee9572..31da094a 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
* struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC
* @hw_lm: LM HW Driver context
* @hw_ctl: CTL Path HW driver context
+ * @hw_dspp: DSPP HW driver context
* @encoder: Encoder attached to this lm & ctl
* @mixer_op_mode: mixer blending operation mode
* @flush_mask: mixer flush mask for ctl, mixer and pipe
@@ -35,6 +36,7 @@
struct sde_crtc_mixer {
struct sde_hw_mixer *hw_lm;
struct sde_hw_ctl *hw_ctl;
+ struct sde_hw_dspp *hw_dspp;
struct drm_encoder *encoder;
u32 mixer_op_mode;
u32 flush_mask;
@@ -58,6 +60,9 @@
* @property_defaults : Array of default values for generic property support
* @stage_cfg : H/w mixer stage configuration
* @debugfs_root : Parent of debugfs node
+ * @feature_list : list of color processing features supported on a crtc
+ * @active_list : list of color processing features are active
+ * @dirty_list : list of color processing features are dirty
*/
struct sde_crtc {
struct drm_crtc base;
@@ -84,6 +89,10 @@
struct sde_hw_stage_cfg stage_cfg;
struct dentry *debugfs_root;
+
+ struct list_head feature_list;
+ struct list_head active_list;
+ struct list_head dirty_list;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 69fbe3a..7289240 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,7 @@
#include "sde_formats.h"
#include "sde_encoder_phys.h"
#include "display_manager.h"
+#include "sde_color_processing.h"
#define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -309,8 +310,11 @@
ret = sde_rm_reserve(&sde_kms->rm, drm_enc, crtc_state,
conn_state, true);
- /* Call to populate mode->crtc* information required by framework */
- drm_mode_set_crtcinfo(adj_mode, 0);
+ if (!ret) {
+ sde_cp_crtc_install_properties(drm_enc->crtc);
+ /* populate mode->crtc* information required by framework */
+ drm_mode_set_crtcinfo(adj_mode, 0);
+ }
MSM_EVT(drm_enc->dev, adj_mode->flags, adj_mode->private_flags);
@@ -437,6 +441,7 @@
SDE_DEBUG_ENC(sde_enc, "cleared master\n");
bs_set(sde_enc, 0);
+ sde_cp_crtc_destroy_properties(drm_enc->crtc);
sde_rm_release(&sde_kms->rm, drm_enc);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 62f2ebb..213f49e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -9,12 +9,25 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
+#include "drm/msm_drm_pp.h"
#include "sde_hw_mdss.h"
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_dspp.h"
+#define PCC_ENABLE BIT(0)
+#define PCC_OP_MODE_OFF 0
+#define PCC_CONST_COEFF_OFF 4
+#define PCC_R_COEFF_OFF 0x10
+#define PCC_G_COEFF_OFF 0x1C
+#define PCC_B_COEFF_OFF 0x28
+#define PCC_RG_COEFF_OFF 0x34
+#define PCC_RB_COEFF_OFF 0x40
+#define PCC_GB_COEFF_OFF 0x4C
+#define PCC_RGB_COEFF_OFF 0x58
+#define PCC_CONST_COEFF_MASK 0xFFFF
+#define PCC_COEFF_MASK 0x3FFFF
+
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
struct sde_mdss_cfg *m,
void __iomem *addr,
@@ -51,8 +64,96 @@
{
}
+void sde_dspp_setup_hue(struct sde_hw_dspp *dspp, void *cfg)
+{
+}
+
void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg)
{
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct drm_msm_pcc *pcc;
+ void __iomem *base;
+
+ if (!hw_cfg || (hw_cfg->len != sizeof(*pcc) && hw_cfg->payload)) {
+ DRM_ERROR(
+ "hw_cfg %pK payload %pK payload size %d exp size %zd\n",
+ hw_cfg, (hw_cfg ? hw_cfg->payload : NULL),
+ ((hw_cfg) ? hw_cfg->len : 0), sizeof(*pcc));
+ return;
+ }
+ base = ctx->hw.base_off + ctx->cap->base;
+
+ /* Turn off feature */
+ if (!hw_cfg->payload) {
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base,
+ PCC_OP_MODE_OFF);
+ return;
+ }
+ DRM_DEBUG_DRIVER("Enable PCC feature\n");
+ pcc = hw_cfg->payload;
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF,
+ pcc->r.c & PCC_CONST_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw,
+ ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 4,
+ pcc->g.c & PCC_CONST_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw,
+ ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 8,
+ pcc->b.c & PCC_CONST_COEFF_MASK);
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF,
+ pcc->r.r & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 4,
+ pcc->g.r & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 8,
+ pcc->b.r & PCC_COEFF_MASK);
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF,
+ pcc->r.g & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 4,
+ pcc->g.g & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 8,
+ pcc->b.g & PCC_COEFF_MASK);
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF,
+ pcc->r.b & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 4,
+ pcc->g.b & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 8,
+ pcc->b.b & PCC_COEFF_MASK);
+
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF,
+ pcc->r.rg & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 4,
+ pcc->g.rg & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 8,
+ pcc->b.rg & PCC_COEFF_MASK);
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF,
+ pcc->r.rb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 4,
+ pcc->g.rb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 8,
+ pcc->b.rb & PCC_COEFF_MASK);
+
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF,
+ pcc->r.gb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 4,
+ pcc->g.gb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 8,
+ pcc->b.gb & PCC_COEFF_MASK);
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF,
+ pcc->r.rgb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw,
+ ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 4,
+ pcc->g.rgb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw,
+ ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 8,
+ pcc->b.rgb & PCC_COEFF_MASK);
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, PCC_ENABLE);
}
void sde_dspp_setup_sharpening(struct sde_hw_dspp *ctx, void *cfg)
@@ -75,10 +176,31 @@
{
}
-static void _setup_dspp_ops(struct sde_hw_dspp_ops *ops,
- unsigned long features)
+static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
{
+ int i = 0;
+
+ for (i = 0; i < SDE_DSPP_MAX; i++) {
+ if (!test_bit(i, &features))
+ continue;
+ switch (i) {
+ case SDE_DSPP_PCC:
+ if (c->cap->sblk->pcc.version ==
+ (SDE_COLOR_PROCESS_VER(0x1, 0x0)))
+ c->ops.setup_pcc = sde_dspp_setup_pcc;
+ break;
+ case SDE_DSPP_HSIC:
+ if (c->cap->sblk->hsic.version ==
+ (SDE_COLOR_PROCESS_VER(0x1, 0x0)))
+ c->ops.setup_hue = sde_dspp_setup_hue;
+ break;
+ default:
+ break;
+ }
+
+ }
}
+
struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
@@ -99,7 +221,7 @@
/* Assign ops */
c->idx = idx;
c->cap = cfg;
- _setup_dspp_ops(&c->ops, c->cap->features);
+ _setup_dspp_ops(c, c->cap->features);
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 6ba161a..2c6e638 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -83,12 +83,41 @@
* @cfg: Pointer to configuration
*/
void (*setup_danger_safe)(struct sde_hw_dspp *ctx, void *cfg);
+
/**
* setup_dither - setup dspp dither
* @ctx: Pointer to dspp context
* @cfg: Pointer to configuration
*/
void (*setup_dither)(struct sde_hw_dspp *ctx, void *cfg);
+
+ /**
+ * setup_hue - setup dspp PA hue
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+ void (*setup_hue)(struct sde_hw_dspp *ctx, void *cfg);
+
+ /**
+ * setup_sat - setup dspp PA saturation
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+ void (*setup_sat)(struct sde_hw_dspp *ctx, void *cfg);
+
+ /**
+ * setup_val - setup dspp PA value
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+ void (*setup_val)(struct sde_hw_dspp *ctx, void *cfg);
+
+ /**
+ * setup_cont - setup dspp PA contrast
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+ void (*setup_cont)(struct sde_hw_dspp *ctx, void *cfg);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index b5d31b9..168975c 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -151,7 +151,7 @@
SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
}
-static void sde_hw_lm_gammacorrection(struct sde_hw_mixer *mixer,
+static void sde_hw_lm_gc(struct sde_hw_mixer *mixer,
void *cfg)
{
}
@@ -167,7 +167,7 @@
ops->setup_blend_config = sde_hw_lm_setup_blend_config;
ops->setup_alpha_out = sde_hw_lm_setup_color3;
ops->setup_border_color = sde_hw_lm_setup_border_color;
- ops->setup_gammcorrection = sde_hw_lm_gammacorrection;
+ ops->setup_gc = sde_hw_lm_gc;
};
struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index 1bde86e..ca671f8 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -60,8 +60,10 @@
void (*setup_border_color)(struct sde_hw_mixer *ctx,
struct sde_mdss_color *color,
u8 border_en);
-
- void (*setup_gammcorrection)(struct sde_hw_mixer *mixer,
+ /**
+ * setup_gc : enable/disable gamma correction feature
+ */
+ void (*setup_gc)(struct sde_hw_mixer *mixer,
void *cfg);
};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index aaad568..3bc521a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -424,4 +424,14 @@
#define SDE_DBG_MASK_TOP (1 << 9)
#define SDE_DBG_MASK_VBIF (1 << 10)
+/**
+ * struct sde_hw_cp_cfg: hardware dspp/lm feature payload.
+ * @payload: Feature specific payload.
+ * @len: Length of the payload.
+ */
+struct sde_hw_cp_cfg {
+ void *payload;
+ u32 len;
+};
+
#endif /* _SDE_HW_MDSS_H */