diff options
author | Gopikrishnaiah Anandan <agopik@codeaurora.org> | 2016-02-25 11:25:11 -0800 |
---|---|---|
committer | Kyle Yan <kyan@codeaurora.org> | 2016-06-07 11:55:10 -0700 |
commit | 68f301791adcd442e10255eafeaeb039d0762170 (patch) | |
tree | 1a68fa693b050fbaaae77e7dc5b675ab9b35cbcb /drivers/video/fbdev | |
parent | 9b03c7ad99bb4e61ad3f684bfe9bef6bdf6d0dc6 (diff) |
msm: mdss: Add PA dither support for msmcobalt
Picture adjustment block on msmcobalt mdss supports dithering module.
Module can be programmed by driver clients for a logical display.
Change adds support for enabling the PA dither block.
Change-Id: I8ae05d0f98a33a8608a4caef93d50e4dabad05a1
Signed-off-by: Gopikrishnaiah Anandan <agopik@codeaurora.org>
Signed-off-by: Ping Li <pingli@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 65 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.h | 11 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c | 103 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h | 5 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_v3.c | 114 |
7 files changed, 289 insertions, 17 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e67a7a60fddb..e7bc1c607d70 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -687,6 +687,7 @@ struct pp_sts_type { u32 sharp_sts; u32 hist_sts; u32 side_sts; + u32 pa_dither_sts; }; struct mdss_pipe_pp_res { @@ -1709,6 +1710,9 @@ int mdss_mdp_dither_config(struct msm_fb_data_type *mfd, int copy_from_kernel); int mdss_mdp_gamut_config(struct msm_fb_data_type *mfd, struct mdp_gamut_cfg_data *config, u32 *copyback); +int mdss_mdp_pa_dither_config(struct msm_fb_data_type *mfd, + struct mdp_dither_cfg_data *config); + int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en); int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int state); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index ab02c2a12efd..0173f73ffe6b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -4089,6 +4089,10 @@ static int mdss_mdp_pp_ioctl(struct msm_fb_data_type *mfd, case mdp_op_calib_dcm_state: ret = mdss_fb_dcm(mfd, mdp_pp.data.calib_dcm.dcm_state); break; + case mdp_op_pa_dither_cfg: + ret = mdss_mdp_pa_dither_config(mfd, + &mdp_pp.data.dither_cfg_data); + break; default: pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n", mdp_pp.op); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index f92d4bb9ed1d..d65985a13cf1 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -355,6 +355,8 @@ static u32 igc_limited[IGC_LUT_ENTRIES] = { #define PP_FLAGS_DIRTY_HIST_COL 0x80 #define PP_FLAGS_DIRTY_PGC 0x100 #define PP_FLAGS_DIRTY_SHARP 0x200 +#define PP_FLAGS_DIRTY_PA_DITHER 0x400 + /* Leave space for future features */ #define PP_FLAGS_RESUME_COMMIT 0x10000000 @@ -2391,6 +2393,12 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) pgc_config->flags); } } + if (flags & PP_FLAGS_DIRTY_PA_DITHER && + pp_ops[PA_DITHER].pp_set_config) { + pp_ops[PA_DITHER].pp_set_config(base, pp_sts, + &mdss_pp_res->pa_dither_cfg[disp_num], + DSPP); + } pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode); @@ -2716,7 +2724,13 @@ int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd) mdss_pp_res->pgc_disp_cfg[disp_num].flags |= MDP_PP_OPS_WRITE; } - + if (pp_sts.pa_dither_sts & PP_STS_ENABLE) { + flags |= PP_FLAGS_DIRTY_PA_DITHER; + if (!(mdss_pp_res->pa_dither_cfg[disp_num].flags + & MDP_PP_OPS_DISABLE)) + mdss_pp_res->pa_dither_cfg[disp_num].flags |= + MDP_PP_OPS_WRITE; + } mdss_pp_res->pp_disp_flags[disp_num] |= flags; mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_RESUME_COMMIT; @@ -7138,7 +7152,7 @@ int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version) ret = -EINVAL; goto exit_version; } - if (version->pp_feature >= PP_FEATURE_MAX) { + if (version->pp_feature >= PP_MAX_FEATURES) { pr_err("invalid feature passed %d\n", version->pp_feature); ret = -EINVAL; goto exit_version; @@ -7509,3 +7523,50 @@ static int pp_ppb_setup(struct mdss_mdp_mixer *mixer) } return ret; } + +int mdss_mdp_pa_dither_config(struct msm_fb_data_type *mfd, + struct mdp_dither_cfg_data *config) +{ + u32 disp_num; + int ret = 0; + struct mdp_pp_cache_res res_cache; + + ret = pp_validate_dspp_mfd_block(mfd, config->block); + if (ret) { + pr_err("Invalid block %d mfd index %d, ret %d\n", + config->block, + (mfd ? mfd->index : -1), ret); + return ret; + } + + if (config->flags & MDP_PP_OPS_READ) { + pr_err("Dither read is not supported\n"); + return -EOPNOTSUPP; + } + + if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + + mutex_lock(&mdss_pp_mutex); + disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0; + res_cache.block = DSPP; + res_cache.mdss_pp_res = mdss_pp_res; + if (pp_ops[PA_DITHER].pp_set_config) { + pr_debug("version of pa dither is %d\n", config->version); + ret = pp_pa_dither_cache_params(config, &res_cache); + if (ret) { + pr_err("pa dither config failed version %d ret %d\n", + config->version, ret); + goto dither_config_exit; + } + } else { + ret = -EINVAL; + goto dither_config_exit; + } + mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA_DITHER; +dither_config_exit: + mutex_unlock(&mdss_pp_mutex); + return ret; +} diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h index c5322d205bf5..9a6e9ea3300c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.h +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h @@ -99,7 +99,7 @@ struct mdp_pp_feature_ops { }; struct mdp_pp_driver_ops { - struct mdp_pp_feature_ops pp_ops[PP_FEATURE_MAX]; + struct mdp_pp_feature_ops pp_ops[PP_MAX_FEATURES]; void (*pp_opmode_config)(int location, struct pp_sts_type *pp_sts, u32 *opmode, int side); int (*get_hist_offset)(u32 block, u32 *ctl_off); @@ -108,6 +108,13 @@ struct mdp_pp_driver_ops { void (*gamut_clk_gate_en)(char __iomem *base_addr); }; +struct mdp_pa_dither_res_data_v1_7 { + uint32_t matrix_sz; + uint32_t matrix_data[MDP_DITHER_DATA_V1_7_SZ]; + uint32_t strength; + uint32_t offset_en; +}; + struct mdss_pp_res_type_v1_7 { u32 pgc_lm_table_c0[MDSS_BLOCK_DISP_NUM][PGC_LUT_ENTRIES]; u32 pgc_lm_table_c1[MDSS_BLOCK_DISP_NUM][PGC_LUT_ENTRIES]; @@ -128,6 +135,7 @@ struct mdss_pp_res_type_v1_7 { struct mdp_gamut_data_v1_7 gamut_v17_data[MDSS_BLOCK_DISP_NUM]; struct mdp_pcc_data_v1_7 pcc_v17_data[MDSS_BLOCK_DISP_NUM]; struct mdp_pa_data_v1_7 pa_v17_data[MDSS_BLOCK_DISP_NUM]; + struct mdp_pa_dither_res_data_v1_7 pa_dither_data[MDSS_BLOCK_DISP_NUM]; }; struct mdss_pp_res_type { @@ -156,6 +164,7 @@ struct mdss_pp_res_type { uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE]; u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE]; struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM]; + struct mdp_dither_cfg_data pa_dither_cfg[MDSS_BLOCK_DISP_NUM]; /* physical info */ struct pp_hist_col_info *dspp_hist; /* diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c index d1b3f1a89812..ec9c1800787f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c @@ -1476,3 +1476,106 @@ exit: pp_info->pcc_cfg_data.cfg_payload = cfg_payload; return ret; } + +static int pp_pa_dither_cache_params_v1_7( + struct mdp_dither_cfg_data *config, + struct mdss_pp_res_type *mdss_pp_res) +{ + struct mdss_pp_res_type_v1_7 *res_cache; + int disp_num, ret = 0; + size_t sz = 0; + struct mdp_pa_dither_res_data_v1_7 *res_data; + struct mdp_pa_dither_data dither_data; + + if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) || + (config->block >= MDP_BLOCK_MAX)) { + pr_err("Invalid config block %d\n", config->block); + return -EINVAL; + } + if (!mdss_pp_res || !mdss_pp_res->pp_data_v1_7) { + pr_err("invalid param mdss_pp_res %p pp_data_res %p\n", + mdss_pp_res, + ((mdss_pp_res) ? mdss_pp_res->pp_data_v1_7 : NULL)); + return -EINVAL; + } + + res_cache = mdss_pp_res->pp_data_v1_7; + if (config->flags & MDP_PP_OPS_READ) { + pr_err("Read op is not supported\n"); + return -EINVAL; + } + + disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; + res_data = &res_cache->pa_dither_data[disp_num]; + if ((config->flags & MDP_PP_OPS_DISABLE) || + !(config->flags & MDP_PP_OPS_WRITE)) { + mdss_pp_res->pa_dither_cfg[disp_num] = *config; + mdss_pp_res->pa_dither_cfg[disp_num].cfg_payload = + (void *) res_data; + return 0; + } + sz = offsetof(struct mdp_pa_dither_data, offset_en) + + sizeof(dither_data.offset_en); + memset(&dither_data, 0, sizeof(dither_data)); + ret = copy_from_user(&dither_data, config->cfg_payload, sz); + if (ret) { + pr_err("failed to copy the dither data ret %d sz %zd", ret, sz); + ret = -EFAULT; + goto exit; + } + if (dither_data.matrix_sz != MDP_DITHER_DATA_V1_7_SZ) { + pr_err("invalid matrix len %d expected %d\n", + dither_data.matrix_sz, MDP_DITHER_DATA_V1_7_SZ); + ret = -EINVAL; + goto exit; + } + res_data->offset_en = dither_data.offset_en; + res_data->strength = dither_data.strength; + res_data->matrix_sz = MDP_DITHER_DATA_V1_7_SZ; + ret = copy_from_user(res_data->matrix_data, + (u8 *)dither_data.matrix_data, + (MDP_DITHER_DATA_V1_7_SZ * sizeof(u32))); + if (ret) { + pr_err("failed to copy the dither matrix ret %d sz %zd", ret, + MDP_DITHER_DATA_V1_7_SZ * sizeof(u32)); + ret = -EFAULT; + goto exit; + } + mdss_pp_res->pa_dither_cfg[disp_num] = *config; + mdss_pp_res->pa_dither_cfg[disp_num].cfg_payload = + (void *) res_data; +exit: + return ret; +} + +int pp_pa_dither_cache_params(struct mdp_dither_cfg_data *config, + struct mdp_pp_cache_res *res_cache) +{ + int ret = 0; + + if (!config || !res_cache) { + pr_err("invalid params config %p res_cache %p\n", + config, res_cache); + return -EINVAL; + } + if (!res_cache->mdss_pp_res && !res_cache->pipe_res) { + pr_err("NULL payload for block %d mdss_pp_res %p pipe_res %p\n", + res_cache->block, res_cache->mdss_pp_res, + res_cache->pipe_res); + return -EINVAL; + } + switch (config->version) { + case mdp_dither_pa_v1_7: + if (res_cache->block == DSPP) + ret = pp_pa_dither_cache_params_v1_7(config, + res_cache->mdss_pp_res); + else + ret = -ENOTSUPP; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h index 13f14f2673e7..242aad3848c2 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 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 @@ -48,4 +48,7 @@ int pp_copy_layer_igc_payload(struct mdp_overlay_pp_params *pp_info); int pp_copy_layer_hist_lut_payload(struct mdp_overlay_pp_params *pp_info); int pp_copy_layer_pa_payload(struct mdp_overlay_pp_params *pp_info); int pp_copy_layer_pcc_payload(struct mdp_overlay_pp_params *pp_info); +int pp_pa_dither_cache_params(struct mdp_dither_cfg_data *config, + struct mdp_pp_cache_res *res_cache); + #endif diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c index 4920c5387e2c..3d277ae5db5f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c @@ -64,6 +64,8 @@ static u32 dither_matrix[DITHER_MATRIX_LEN] = { static u32 dither_depth_map[DITHER_DEPTH_MAP_INDEX] = { 0, 0, 0, 0, 0, 1, 2, 3, 3}; +#define PA_DITHER_REG_OFF 0x2C + /* histogram prototypes */ static int pp_get_hist_offset(u32 block, u32 *ctl_off); static int pp_hist_set_config(char __iomem *base_addr, @@ -82,13 +84,7 @@ static int pp_hist_lut_get_version(u32 *version); static void pp_hist_lut_opmode_config(char __iomem *base_addr, struct pp_sts_type *pp_sts); -static int pp_pa_set_config(char __iomem *base_addr, - struct pp_sts_type *pp_sts, void *cfg_data, - u32 block_type); -static int pp_pa_get_config(char __iomem *base_addr, void *cfg_data, - u32 block_type, u32 disp_num); -static int pp_pa_get_version(u32 *version); - +/* dither prototypes */ static int pp_dither_get_config(char __iomem *base_addr, void *cfg_data, u32 block_type, u32 disp_num); static int pp_dither_set_config(char __iomem *base_addr, @@ -96,22 +92,32 @@ static int pp_dither_set_config(char __iomem *base_addr, u32 block_type); static int pp_dither_get_version(u32 *version); -static void pp_opmode_config(int location, struct pp_sts_type *pp_sts, - u32 *opmode, int side); - +/* PA prototypes */ +static int pp_pa_set_config(char __iomem *base_addr, + struct pp_sts_type *pp_sts, void *cfg_data, + u32 block_type); +static int pp_pa_get_config(char __iomem *base_addr, void *cfg_data, + u32 block_type, u32 disp_num); +static int pp_pa_get_version(u32 *version); static void pp_pa_set_global_adj_regs(char __iomem *base_addr, struct mdp_pa_data_v1_7 *pa_data, u32 flag); - static void pp_pa_set_mem_col(char __iomem *base_addr, struct mdp_pa_data_v1_7 *pa_data, u32 flags); - static void pp_pa_set_six_zone(char __iomem *base_addr, struct mdp_pa_data_v1_7 *pa_data, u32 flags); - static void pp_pa_opmode_config(char __iomem *base_addr, struct pp_sts_type *pp_sts); +/* PA dither prototypes */ +static int pp_pa_dither_get_version(u32 *version); +static int pp_pa_dither_set_config(char __iomem *base_addr, + struct pp_sts_type *pp_sts, void *cfg_data, + u32 block_type); + +static void pp_opmode_config(int location, struct pp_sts_type *pp_sts, + u32 *opmode, int side); + void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops) { void *pp_cfg = NULL; @@ -144,6 +150,10 @@ void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops) ops->pp_ops[DITHER].pp_get_config = pp_dither_get_config; ops->pp_ops[DITHER].pp_get_version = pp_dither_get_version; + ops->pp_ops[PA_DITHER].pp_get_version = pp_pa_dither_get_version; + ops->pp_ops[PA_DITHER].pp_set_config = pp_pa_dither_set_config; + ops->pp_ops[PA_DITHER].pp_get_config = NULL; + /* Set opmode pointers */ ops->pp_opmode_config = pp_opmode_config; @@ -817,3 +827,81 @@ static void pp_pa_opmode_config(char __iomem *base_addr, writel_relaxed(opmode, base_addr + PA_OP_MODE_REG_OFF); } + +static int pp_pa_dither_get_version(u32 *version) +{ + if (!version) { + pr_err("invalid param version"); + return -EINVAL; + } + *version = mdp_dither_pa_v1_7; + return 0; +} + +static int pp_pa_dither_set_config(char __iomem *base_addr, + struct pp_sts_type *pp_sts, void *cfg_data, + u32 block_type) +{ + struct mdp_dither_cfg_data *dither_cfg_data = NULL; + struct mdp_pa_dither_res_data_v1_7 *dither_data = NULL; + u32 *pdata; + u32 opmode = 0, data = 0, i = 0; + char __iomem *opmode_addr = NULL, *matrix_addr = NULL; + + if (!base_addr || !cfg_data || !pp_sts) { + pr_err("invalid params base_addr %p cfg_data %p pp_sts_type %p\n", + base_addr, cfg_data, pp_sts); + return -EINVAL; + } + if (block_type != DSPP) { + pr_err("Invalid block type %d\n", block_type); + return -EINVAL; + } + + dither_cfg_data = (struct mdp_dither_cfg_data *) cfg_data; + if (dither_cfg_data->version != mdp_dither_pa_v1_7) { + pr_err("invalid pa dither version %d\n", + dither_cfg_data->version); + return -EINVAL; + } + if (!(dither_cfg_data->flags & ~(MDP_PP_OPS_READ))) { + pr_debug("only read ops is set %d", dither_cfg_data->flags); + return 0; + } + opmode_addr = base_addr + PA_DSPP_BLOCK_REG_OFF + PA_DITHER_REG_OFF; + if (dither_cfg_data->flags & MDP_PP_OPS_DISABLE || + !(dither_cfg_data->flags & MDP_PP_OPS_WRITE)) { + pr_debug("Disable pa dither/No write ops set flags %x", + dither_cfg_data->flags); + goto dither_set_sts; + } + matrix_addr = opmode_addr + 4; + dither_data = (struct mdp_pa_dither_res_data_v1_7 *) + dither_cfg_data->cfg_payload; + if (!dither_data) { + pr_err("invalid payload for dither\n"); + return -EINVAL; + } + pdata = dither_data->matrix_data; + for (i = 0; i < MDP_DITHER_DATA_V1_7_SZ; i += 4) { + data = (pdata[i] & REG_MASK(4)) | + ((pdata[i + 1] & REG_MASK(4)) << 4) | + ((pdata[i + 2] & REG_MASK(4)) << 8) | + ((pdata[i + 3] & REG_MASK(4)) << 12); + writel_relaxed(data, matrix_addr); + matrix_addr += 4; + } + opmode = BIT(0); + opmode |= (dither_data->offset_en) ? BIT(1) : 0; + opmode |= ((dither_data->strength) & REG_MASK(4)) << 4; + +dither_set_sts: + if (dither_cfg_data->flags & MDP_PP_OPS_DISABLE) { + pp_sts->pa_dither_sts &= ~PP_STS_ENABLE; + writel_relaxed(0, opmode_addr); + } else if (dither_cfg_data->flags & MDP_PP_OPS_ENABLE) { + pp_sts->pa_dither_sts |= PP_STS_ENABLE; + writel_relaxed(opmode, opmode_addr); + } + return 0; +} |