summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorGopikrishnaiah Anandan <agopik@codeaurora.org>2016-06-23 11:43:08 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-10-04 14:11:47 -0700
commit3c858bf63e2bef324adda789a5539eb0c74933b4 (patch)
tree5091add2b12a5634fdcdd7a061e13c346de39eff /drivers/gpu
parente38167ab67a7cdc0125cfb059824ee3a595e8c2c (diff)
drm/msm: Add support for PA vLut feature
Picture adjustment block supports vLut block which can enhance the contrast of the pixels. Change adds support to expose the feature to user-space and program the vLut registers for the display. Change-Id: I9822f9711b9048c5db8c313204a6ba64e013f8a9 Signed-off-by: Gopikrishnaiah Anandan <agopik@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/sde/sde_color_processing.c186
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_dspp.c70
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_dspp.h7
5 files changed, 225 insertions, 48 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index e2302b9fa432..1f912770b626 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -22,7 +22,7 @@
#include "sde_hw_dspp.h"
#include "sde_hw_lm.h"
-struct sde_color_process_node {
+struct sde_cp_node {
u32 property_id;
u32 prop_flags;
u32 feature;
@@ -39,7 +39,7 @@ struct sde_color_process_node {
struct sde_cp_prop_attach {
struct drm_crtc *crtc;
struct drm_property *prop;
- struct sde_color_process_node *prop_node;
+ struct sde_cp_node *prop_node;
const struct sde_pp_blk *pp_blk;
u32 feature;
void *ops;
@@ -62,6 +62,7 @@ enum {
SDE_CP_CRTC_DSPP_DITHER,
SDE_CP_CRTC_DSPP_HIST,
SDE_CP_CRTC_DSPP_AD,
+ SDE_CP_CRTC_DSPP_VLUT,
SDE_CP_CRTC_DSPP_MAX,
/* DSPP features end */
@@ -84,8 +85,43 @@ enum {
(p)->val = val; \
} while (0)
-static int sde_cp_disable_crtc_blob_property(
- struct sde_color_process_node *prop_node)
+static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
+ struct sde_hw_cp_cfg *hw_cfg,
+ bool *feature_enabled)
+{
+
+ struct drm_property_blob *blob = NULL;
+
+ memset(hw_cfg, 0, sizeof(*hw_cfg));
+ *feature_enabled = false;
+
+ blob = prop_node->blob_ptr;
+ if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
+ if (blob) {
+ hw_cfg->len = blob->length;
+ hw_cfg->payload = blob->data;
+ *feature_enabled = true;
+ }
+ } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
+ /* Check if local blob is Set */
+ if (!blob) {
+ hw_cfg->len = sizeof(prop_node->prop_val);
+ if (prop_node->prop_val)
+ hw_cfg->payload = &prop_node->prop_val;
+ } else {
+ hw_cfg->len = (prop_node->prop_val) ? blob->length :
+ 0;
+ hw_cfg->payload = (prop_node->prop_val) ? blob->data
+ : NULL;
+ }
+ if (prop_node->prop_val)
+ *feature_enabled = true;
+ } else {
+ DRM_ERROR("property type is not supported\n");
+ }
+}
+
+static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
{
struct drm_property_blob *blob = prop_node->blob_ptr;
@@ -96,24 +132,85 @@ static int sde_cp_disable_crtc_blob_property(
return 0;
}
-static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
- struct drm_property *property,
- struct sde_color_process_node *prop_node)
+static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
+{
+ int ret = -EINVAL;
+ bool found = false;
+ struct sde_cp_node *prop_node = NULL;
+ struct drm_property_blob *blob_ptr;
+ struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
+
+ list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
+ if (prop_node->feature == feature) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found || prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
+ DRM_ERROR("local blob create failed prop found %d flags %d\n",
+ found, prop_node->prop_flags);
+ return ret;
+ }
+
+ blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
+ ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
+ if (!ret)
+ prop_node->blob_ptr = blob_ptr;
+
+ return ret;
+}
+
+static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
+{
+ if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
+ prop_node->blob_ptr)
+ drm_property_unreference_blob(prop_node->blob_ptr);
+}
+
+static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
+ uint64_t val)
{
int ret = 0;
+ struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
- if (property->flags & DRM_MODE_PROP_BLOB) {
- ret = sde_cp_disable_crtc_blob_property(prop_node);
- } else if (property->flags & DRM_MODE_PROP_RANGE) {
+ if (!blob_ptr) {
+ prop_node->prop_val = val;
+ return 0;
+ }
+
+ if (!val) {
prop_node->prop_val = 0;
- ret = 0;
+ return 0;
}
+
+ ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
+ if (ret) {
+ DRM_ERROR("failed to get the property info ret %d", ret);
+ ret = -EFAULT;
+ } else {
+ prop_node->prop_val = val;
+ }
+
+ return ret;
+}
+
+static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
+ struct drm_property *property,
+ struct sde_cp_node *prop_node)
+{
+ int ret = -EINVAL;
+
+ if (property->flags & DRM_MODE_PROP_BLOB)
+ ret = sde_cp_disable_crtc_blob_property(prop_node);
+ else if (property->flags & DRM_MODE_PROP_RANGE)
+ ret = sde_cp_handle_range_property(prop_node, 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 sde_cp_node *prop_node,
+ uint64_t val)
{
struct drm_property_blob *blob = NULL;
@@ -136,17 +233,15 @@ static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
struct drm_property *property,
- struct sde_color_process_node *prop_node,
+ struct sde_cp_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;
- }
+ else if (property->flags & DRM_MODE_PROP_RANGE)
+ ret = sde_cp_handle_range_property(prop_node, val);
return ret;
}
@@ -215,7 +310,7 @@ static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
u32 feature)
{
struct drm_property *prop;
- struct sde_color_process_node *prop_node = NULL;
+ struct sde_cp_node *prop_node = NULL;
struct msm_drm_private *priv;
struct sde_cp_prop_attach prop_attach;
uint64_t val = 0;
@@ -257,7 +352,7 @@ static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
uint64_t val)
{
struct drm_property *prop;
- struct sde_color_process_node *prop_node = NULL;
+ struct sde_cp_node *prop_node = NULL;
struct msm_drm_private *priv;
struct sde_cp_prop_attach prop_attach;
@@ -295,7 +390,7 @@ static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
u32 feature, void *ops)
{
struct drm_property *prop;
- struct sde_color_process_node *prop_node = NULL;
+ struct sde_cp_node *prop_node = NULL;
struct msm_drm_private *priv;
uint64_t val = 0;
struct sde_cp_prop_attach prop_attach;
@@ -331,15 +426,14 @@ static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
}
-static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
+static void sde_cp_crtc_setfeature(struct sde_cp_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;
+ u32 num_mixers = sde_crtc->num_mixers;
int i = 0;
bool is_dspp = true;
+ bool feature_enabled = false;
if (!prop_node->dspp_feature_op && !prop_node->lm_feature_op) {
DRM_ERROR("ops not set for dspp/lm\n");
@@ -347,21 +441,7 @@ static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
}
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;
- }
+ sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
for (i = 0; i < num_mixers; i++) {
if (is_dspp) {
@@ -377,7 +457,7 @@ static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
}
}
- if (blob || val) {
+ if (feature_enabled) {
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);
@@ -394,7 +474,7 @@ 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_cp_node *prop_node = NULL, *n = NULL;
struct sde_hw_ctl *ctl;
uint32_t flush_mask = 0;
u32 num_mixers = 0, i = 0;
@@ -549,6 +629,19 @@ void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
sde_cp_crtc_install_immutable_property(crtc,
feature_name, SDE_CP_CRTC_DSPP_AD);
break;
+ case SDE_DSPP_VLUT:
+ snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+ "SDE_DSPP_VLUT_V",
+ (hw_dspp->cap->sblk->vlut.version >> 16));
+ sde_cp_crtc_install_range_property(crtc, feature_name,
+ &hw_dspp->cap->sblk->vlut,
+ SDE_CP_CRTC_DSPP_VLUT, hw_dspp->ops.setup_vlut,
+ 0, U64_MAX, 0);
+ /* TODO: if blob creation fails destroy the property */
+ sde_cp_create_local_blob(crtc,
+ SDE_CP_CRTC_DSPP_VLUT,
+ sizeof(struct drm_msm_pa_vlut));
+ break;
default:
break;
}
@@ -585,7 +678,7 @@ 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_cp_node *prop_node = NULL;
struct sde_crtc *sde_crtc = NULL;
int ret = 0;
u8 found = 0;
@@ -632,7 +725,7 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
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_cp_node *prop_node = NULL;
struct sde_crtc *sde_crtc = NULL;
int ret = -EINVAL;
@@ -661,7 +754,7 @@ int sde_cp_crtc_get_property(struct drm_crtc *crtc,
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;
+ struct sde_cp_node *prop_node = NULL, *n = NULL;
if (!crtc) {
DRM_ERROR("invalid crtc %pK\n", crtc);
@@ -683,6 +776,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
list_del_init(&prop_node->active_list);
list_del_init(&prop_node->dirty_list);
list_del_init(&prop_node->feature_list);
+ sde_cp_destroy_local_blob(prop_node);
kfree(prop_node);
}
@@ -694,7 +788,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
void sde_cp_crtc_suspend(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc = NULL;
- struct sde_color_process_node *prop_node = NULL, *n = NULL;
+ struct sde_cp_node *prop_node = NULL, *n = NULL;
if (!crtc) {
DRM_ERROR("crtc %pK\n", crtc);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 2f17478c0694..a8d4f203461d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -127,7 +127,9 @@ enum {
* @SDE_DSPP_SIXZONE Six zone block
* @SDE_DSPP_GAMUT Gamut bloc
* @SDE_DSPP_DITHER Dither block
- * @SDE_DSPP_HIST Histogram bloc
+ * @SDE_DSPP_HIST Histogram block
+ * @SDE_DSPP_VLUT PA VLUT block
+ * @SDE_DSPP_AD AD block
* @SDE_DSPP_MAX maximum value
*/
enum {
@@ -140,6 +142,7 @@ enum {
SDE_DSPP_GAMUT,
SDE_DSPP_DITHER,
SDE_DSPP_HIST,
+ SDE_DSPP_VLUT,
SDE_DSPP_AD,
SDE_DSPP_MAX
};
@@ -358,6 +361,7 @@ struct sde_dspp_sub_blks {
struct sde_pp_blk dither;
struct sde_pp_blk hist;
struct sde_pp_blk ad;
+ struct sde_pp_blk vlut;
};
struct sde_pingpong_sub_blks {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
index 9ff4c4bfe239..437f02718174 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -41,7 +41,7 @@
(BIT(SDE_DSPP_IGC) | BIT(SDE_DSPP_PCC) |\
BIT(SDE_DSPP_GC) | BIT(SDE_DSPP_HSIC) | BIT(SDE_DSPP_GAMUT) |\
BIT(SDE_DSPP_DITHER) | BIT(SDE_DSPP_HIST) | BIT(SDE_DSPP_MEMCOLOR) |\
- BIT(SDE_DSPP_SIXZONE) | BIT(SDE_DSPP_AD))
+ BIT(SDE_DSPP_SIXZONE) | BIT(SDE_DSPP_AD) | BIT(SDE_DSPP_VLUT))
#define PINGPONG_17X_MASK \
(BIT(SDE_PINGPONG_TE) | BIT(SDE_PINGPONG_DSC))
@@ -362,6 +362,8 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
.ad = {.id = SDE_DSPP_AD, .base = 0x00, .len = 0x0,
.version = SDE_COLOR_PROCESS_VER(0x3, 0x0)},
+ .vlut = {.id = SDE_DSPP_VLUT, .base = 0x1400, .len = 0x0,
+ .version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
};
/* PINGPONG capability */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 52b51ed360d8..21bab265b860 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -28,6 +28,28 @@
#define PCC_CONST_COEFF_MASK 0xFFFF
#define PCC_COEFF_MASK 0x3FFFF
+#define REG_MASK(n) ((BIT(n)) - 1)
+#define PA_SZ_VAL_MASK BIT(31)
+#define PA_SZ_SAT_MASK BIT(30)
+#define PA_SZ_HUE_MASK BIT(29)
+#define PA_CONT_MASK BIT(28)
+#define PA_VAL_MASK BIT(27)
+#define PA_SAT_MASK BIT(26)
+#define PA_HUE_MASK BIT(25)
+#define PA_LUTV_MASK BIT(19)
+#define PA_HIST_MASK BIT(16)
+#define PA_MEM_SKY_MASK BIT(7)
+#define PA_MEM_FOL_MASK BIT(6)
+#define PA_MEM_SKIN_MASK BIT(5)
+#define PA_ENABLE BIT(20)
+
+#define PA_ENABLE_MASK (PA_SZ_VAL_MASK | PA_SZ_SAT_MASK | PA_SZ_HUE_MASK \
+ | PA_CONT_MASK | PA_VAL_MASK | PA_SAT_MASK \
+ | PA_HUE_MASK | PA_LUTV_MASK | PA_HIST_MASK \
+ | PA_MEM_SKY_MASK | PA_MEM_FOL_MASK | PA_MEM_SKIN_MASK)
+
+#define PA_LUT_SWAP_OFF 0x234
+
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
struct sde_mdss_cfg *m,
void __iomem *addr,
@@ -68,6 +90,49 @@ void sde_dspp_setup_hue(struct sde_hw_dspp *dspp, void *cfg)
{
}
+void sde_dspp_setup_vlut(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_pa_vlut *payload = NULL;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ u32 op_mode, tmp;
+ int i = 0, j = 0;
+
+ if (!hw_cfg || (hw_cfg->payload && hw_cfg->len !=
+ sizeof(struct drm_msm_pa_vlut))) {
+ DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n",
+ hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
+ ((hw_cfg) ? hw_cfg->len : 0),
+ sizeof(struct drm_msm_pa_vlut));
+ return;
+ }
+ op_mode = SDE_REG_READ(&ctx->hw, 0);
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("Disable vlut feature\n");
+ /**
+ * In the PA_VLUT disable case, remove PA_VLUT enable bit(19)
+ * first, then check whether any other PA sub-features are
+ * enabled or not. If none of the sub-features are enabled,
+ * remove the PA global enable bit(20).
+ */
+ op_mode &= ~((u32)PA_LUTV_MASK);
+ if (!(op_mode & PA_ENABLE_MASK))
+ op_mode &= ~((u32)PA_ENABLE);
+ SDE_REG_WRITE(&ctx->hw, 0, op_mode);
+ return;
+ }
+ payload = hw_cfg->payload;
+ DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
+ for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) {
+ tmp = (payload->val[i] & REG_MASK(10)) |
+ ((payload->val[i + 1] & REG_MASK(10)) << 16);
+ SDE_REG_WRITE(&ctx->hw, (ctx->cap->sblk->vlut.base + j),
+ tmp);
+ }
+ SDE_REG_WRITE(&ctx->hw, PA_LUT_SWAP_OFF, 1);
+ op_mode |= PA_ENABLE | PA_LUTV_MASK;
+ SDE_REG_WRITE(&ctx->hw, 0, op_mode);
+}
+
void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg)
{
struct sde_hw_cp_cfg *hw_cfg = cfg;
@@ -194,6 +259,11 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
(SDE_COLOR_PROCESS_VER(0x1, 0x0)))
c->ops.setup_hue = sde_dspp_setup_hue;
break;
+ case SDE_DSPP_VLUT:
+ if (c->cap->sblk->vlut.version ==
+ (SDE_COLOR_PROCESS_VER(0x1, 0x0))) {
+ c->ops.setup_vlut = sde_dspp_setup_vlut;
+ }
default:
break;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index d65bb2253af2..71f2658fa2fc 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -118,6 +118,13 @@ struct sde_hw_dspp_ops {
* @cfg: Pointer to configuration
*/
void (*setup_cont)(struct sde_hw_dspp *ctx, void *cfg);
+
+ /**
+ * setup_vlut - setup dspp PA VLUT
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+ void (*setup_vlut)(struct sde_hw_dspp *ctx, void *cfg);
};
/**