diff options
| author | Gopikrishnaiah Anandan <agopik@codeaurora.org> | 2016-06-23 11:43:08 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-10-04 14:11:47 -0700 |
| commit | 3c858bf63e2bef324adda789a5539eb0c74933b4 (patch) | |
| tree | 5091add2b12a5634fdcdd7a061e13c346de39eff /drivers/gpu | |
| parent | e38167ab67a7cdc0125cfb059824ee3a595e8c2c (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.c | 186 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_dspp.c | 70 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_dspp.h | 7 |
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); }; /** |
