summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPing Li <pingli@codeaurora.org>2014-11-06 14:40:22 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:35:43 -0700
commitea14d7ee8802ba20a68ada8501b6f537435b88f1 (patch)
treedb79ac51318139440a9469b4e13e4d6fddb4c0a8
parent2026a16aedc0ff374e78aed8ec9a929e681d37b8 (diff)
msm: mdss: Add PA LUT support in DSPP for Thulium
MDP block supports picture adjustment LUTv in the DSPPs (destination surface processing pipes) which can be enabled or disabled by driver clients. This change adds the support in post-processing driver to allows configuration on PA LUTv in DSPPs. Change-Id: I7a0d436e7fdd921c55d12fddef33f5ba6c14ba00 Signed-off-by: Ping Li <pingli@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c49
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c84
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c185
-rw-r--r--include/uapi/linux/msm_mdp.h6
6 files changed, 321 insertions, 10 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 2b0ddce10cba..f073a9201cc4 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -222,8 +222,6 @@ static int mdss_mdp_hscl_filter[] = {
#define PP_SSPP 0
#define PP_DSPP 1
-#define PP_STS_GAMUT_FIRST 0x2
-
#define PP_STS_PA_HUE_MASK 0x2
#define PP_STS_PA_SAT_MASK 0x4
#define PP_STS_PA_VAL_MASK 0x8
@@ -1723,8 +1721,19 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
}
}
- pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
- pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
+ if (flags & PP_FLAGS_DIRTY_ENHIST) {
+ if (!pp_ops[HIST_LUT].pp_set_config) {
+ pp_enhist_config(flags,
+ base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+ pp_sts,
+ &mdss_pp_res->enhist_disp_cfg[disp_num]);
+ } else {
+ /* Pass dspp num using block */
+ mdss_pp_res->enhist_disp_cfg[disp_num].block = dspp_num;
+ pp_ops[HIST_LUT].pp_set_config(base, pp_sts,
+ &mdss_pp_res->enhist_disp_cfg[disp_num], DSPP);
+ }
+ }
if (pp_sts->enhist_sts & PP_STS_ENABLE &&
!(pp_sts->pa_sts & PP_STS_ENABLE)) {
@@ -3289,7 +3298,7 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config,
{
int i, ret = 0;
u32 disp_num, dspp_num = 0;
- char __iomem *hist_addr;
+ char __iomem *hist_addr = NULL, *base_addr = NULL;
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
@@ -3306,9 +3315,22 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config,
goto enhist_config_exit;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ base_addr = mdss_mdp_get_dspp_addr_off(dspp_num);
+ if (IS_ERR_OR_NULL(base_addr)) {
+ pr_err("invalid base addr %p\n",
+ base_addr);
+ ret = -EINVAL;
+ goto hist_lut_clk_off;
+ }
+ hist_addr = base_addr + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+ if (pp_ops[HIST_LUT].pp_get_config) {
+ ret = pp_ops[HIST_LUT].pp_get_config(base_addr, config,
+ DSPP, disp_num);
+ if (ret)
+ pr_err("hist_lut get config failed %d\n", ret);
+ goto hist_lut_clk_off;
+ }
- hist_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
- MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
mdss_pp_res->enhist_lut[disp_num][i] =
readl_relaxed(hist_addr);
@@ -3320,8 +3342,20 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config,
goto enhist_config_exit;
}
*copyback = 1;
+hist_lut_clk_off:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
} else {
+ if (pp_ops[HIST_LUT].pp_set_config) {
+ ret = pp_hist_lut_cache_params(config, mdss_pp_res);
+ if (ret) {
+ pr_err("hist_lut config failed version %d ret %d\n",
+ config->version, ret);
+ ret = -EFAULT;
+ goto enhist_config_exit;
+ } else {
+ goto enhist_set_dirty;
+ }
+ }
if (copy_from_user(&mdss_pp_res->enhist_lut[disp_num][0],
config->data, ENHIST_LUT_ENTRIES * sizeof(u32))) {
ret = -EFAULT;
@@ -3330,6 +3364,7 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config,
mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
mdss_pp_res->enhist_disp_cfg[disp_num].data =
&mdss_pp_res->enhist_lut[disp_num][0];
+enhist_set_dirty:
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ENHIST;
}
enhist_config_exit:
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h
index 0f0b7575e11e..1db69142706b 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h
@@ -21,6 +21,8 @@
/* PP STS related flags */
#define PP_STS_ENABLE 0x1
+#define PP_STS_GAMUT_FIRST 0x2
+#define PP_STS_PA_LUT_FIRST 0x4
/* Demo mode macros */
#define MDSS_SIDE_NONE 0
@@ -91,7 +93,9 @@ struct mdp_pp_driver_ops {
struct mdss_pp_res_type_v1_7 {
u32 igc_table_c0_c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
u32 igc_table_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+ u32 hist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
struct mdp_igc_lut_data_v1_7 igc_v17_data[MDSS_BLOCK_DISP_NUM];
+ struct mdp_hist_lut_data_v1_7 hist_lut_v17_data[MDSS_BLOCK_DISP_NUM];
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];
};
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 5bc73a63c2af..92cb78353048 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
@@ -21,6 +21,90 @@
#include "mdss_mdp_pp.h"
#include "mdss_mdp_pp_cache_config.h"
+static int pp_hist_lut_cache_params_v1_7(struct mdp_hist_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res)
+{
+ u32 disp_num;
+ struct mdss_pp_res_type_v1_7 *res_cache = NULL;
+ struct mdp_hist_lut_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
+ int ret = 0;
+
+ if (!config || !mdss_pp_res) {
+ pr_err("invalid param config %p pp_res %p\n",
+ config, mdss_pp_res);
+ return -EINVAL;
+ }
+ 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->pp_data_res) {
+ pr_err("invalid pp_data_res %p\n", mdss_pp_res->pp_data_res);
+ return -EINVAL;
+ }
+
+ res_cache = mdss_pp_res->pp_data_res;
+ if (config->ops & MDP_PP_OPS_READ) {
+ pr_err("read op is not supported\n");
+ return -EINVAL;
+ } else {
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+ mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
+ v17_cache_data = &res_cache->hist_lut_v17_data[disp_num];
+ mdss_pp_res->enhist_disp_cfg[disp_num].cfg_payload =
+ (void *) v17_cache_data;
+
+ if (copy_from_user(&v17_usr_config, config->cfg_payload,
+ sizeof(v17_usr_config))) {
+ pr_err("failed to copy v17 hist_lut\n");
+ ret = -EFAULT;
+ return ret;
+ }
+ if ((config->ops & MDP_PP_OPS_DISABLE)) {
+ pr_debug("disable hist_lut\n");
+ ret = 0;
+ return ret;
+ }
+ memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config));
+ if (v17_usr_config.len != ENHIST_LUT_ENTRIES) {
+ pr_err("Invalid table size %d exp %d\n",
+ v17_usr_config.len, ENHIST_LUT_ENTRIES);
+ ret = -EINVAL;
+ return ret;
+ }
+ v17_cache_data->data = &res_cache->hist_lut[disp_num][0];
+ if (copy_from_user(v17_cache_data->data, v17_usr_config.data,
+ v17_usr_config.len * sizeof(u32))) {
+ pr_err("failed to copy v17 hist_lut->data\n");
+ ret = -EFAULT;
+ return ret;
+ }
+ }
+ return ret;
+}
+
+int pp_hist_lut_cache_params(struct mdp_hist_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res)
+{
+ int ret = 0;
+ if (!config || !mdss_pp_res) {
+ pr_err("invalid param config %p pp_res %p\n",
+ config, mdss_pp_res);
+ return -EINVAL;
+ }
+ switch (config->version) {
+ case mdp_hist_lut_v1_7:
+ ret = pp_hist_lut_cache_params_v1_7(config, mdss_pp_res);
+ break;
+ default:
+ pr_err("unsupported hist_lut version %d\n",
+ config->version);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
static int pp_gamut_cache_params_v1_7(struct mdp_gamut_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res)
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 2b7c701627a4..905c5f93b061 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h
@@ -16,6 +16,9 @@
#define MDSS_MDP_CACHE_CONFIG_H
#include "mdss_mdp_pp.h"
+int pp_hist_lut_cache_params(struct mdp_hist_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res);
+
int pp_gamut_cache_params(struct mdp_gamut_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res);
int pp_pcc_cache_params(struct mdp_pcc_cfg_data *config,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
index 2cb90eb328e5..43002de9c442 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
@@ -62,8 +62,24 @@
#define IGC_DATA_MASK (BIT(12) - 1)
#define IGC_DSPP_OP_MODE_EN BIT(0)
+
+#define MDSS_MDP_DSPP_OP_PA_LUTV_FIRST_EN BIT(21)
+#define REG_SSPP_VIG_HIST_LUT_BASE 0x1200
+#define REG_DSPP_HIST_LUT_BASE 0x1400
+#define REG_SSPP_VIG_HIST_SWAP_BASE 0x100
+#define REG_DSPP_HIST_SWAP_BASE 0x234
+#define ENHIST_LOWER_VALUE_MASK 0x3FF
+#define ENHIST_UPPER_VALUE_MASK 0x3FF0000
+#define ENHIST_BIT_SHIFT 16
+
static struct mdss_pp_res_type_v1_7 config_data;
+static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num);
+static int pp_hist_lut_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);
@@ -125,9 +141,9 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
ops->pp_ops[QSEED].pp_set_config = NULL;
ops->pp_ops[QSEED].pp_get_config = NULL;
- /* PA_LUT ops */
- ops->pp_ops[HIST_LUT].pp_set_config = NULL;
- ops->pp_ops[HIST_LUT].pp_get_config = NULL;
+ /* HIST_LUT ops */
+ ops->pp_ops[HIST_LUT].pp_set_config = pp_hist_lut_set_config;
+ ops->pp_ops[HIST_LUT].pp_get_config = pp_hist_lut_get_config;
/* Set opmode pointers */
ops->pp_opmode_config = pp_opmode_config;
@@ -152,6 +168,13 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
case DSPP:
if (pp_sts_is_enabled(pp_sts->igc_sts, side))
*opmode |= IGC_DSPP_OP_MODE_EN;
+ if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+ *opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN |
+ MDSS_MDP_DSPP_OP_PA_EN;
+ if (pp_sts->enhist_sts & PP_STS_PA_LUT_FIRST)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_LUTV_FIRST_EN;
+ }
+
break;
case LM:
break;
@@ -162,6 +185,162 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
return;
}
+static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num)
+{
+
+ int ret = 0, i = 0;
+ char __iomem *hist_addr;
+ u32 sz = 0, temp = 0, *data = NULL;
+ struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
+ struct mdp_hist_lut_data *lut_cfg_data = NULL;
+
+ if (!base_addr || !cfg_data) {
+ pr_err("invalid params base_addr %p cfg_data %p\n",
+ base_addr, cfg_data);
+ return -EINVAL;
+ }
+
+ lut_cfg_data = (struct mdp_hist_lut_data *) cfg_data;
+ if (!(lut_cfg_data->ops & MDP_PP_OPS_READ)) {
+ pr_err("read ops not set for hist_lut %d\n", lut_cfg_data->ops);
+ return 0;
+ }
+ if (lut_cfg_data->version != mdp_hist_lut_v1_7 ||
+ !lut_cfg_data->cfg_payload) {
+ pr_err("invalid hist_lut version %d payload %p\n",
+ lut_cfg_data->version, lut_cfg_data->cfg_payload);
+ return -EINVAL;
+ }
+ lut_data = lut_cfg_data->cfg_payload;
+ if (lut_data->len != ENHIST_LUT_ENTRIES) {
+ pr_err("invalid hist_lut len %d", lut_data->len);
+ return -EINVAL;
+ }
+ sz = ENHIST_LUT_ENTRIES * sizeof(u32);
+ if (!access_ok(VERIFY_WRITE, lut_data->data, sz)) {
+ pr_err("invalid lut address for hist_lut sz %d\n", sz);
+ return -EFAULT;
+ }
+
+ switch (block_type) {
+ case SSPP_VIG:
+ hist_addr = base_addr + REG_SSPP_VIG_HIST_LUT_BASE;
+ break;
+ case DSPP:
+ hist_addr = base_addr + REG_DSPP_HIST_LUT_BASE;
+ break;
+ default:
+ pr_err("Invalid block type %d\n", block_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ pr_err("Failed to read hist_lut table ret %d", ret);
+ return ret;
+ }
+
+ data = kzalloc(sz, GFP_KERNEL);
+ if (!data) {
+ pr_err("allocation failed for hist_lut size %d\n", sz);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ENHIST_LUT_ENTRIES; i += 2) {
+ temp = readl_relaxed(hist_addr);
+ data[i] = temp & ENHIST_LOWER_VALUE_MASK;
+ data[i + 1] =
+ (temp & ENHIST_UPPER_VALUE_MASK) >> ENHIST_BIT_SHIFT;
+ hist_addr += 4;
+ }
+ if (copy_to_user(lut_data->data, data, sz)) {
+ pr_err("faild to copy the hist_lut back to user\n");
+ ret = -EFAULT;
+ }
+ kfree(data);
+ return ret;
+}
+
+static int pp_hist_lut_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type)
+{
+ int ret = 0, i = 0;
+ u32 temp = 0;
+ struct mdp_hist_lut_data *lut_cfg_data = NULL;
+ struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
+ char __iomem *hist_addr = NULL, *swap_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;
+ }
+
+ lut_cfg_data = (struct mdp_hist_lut_data *) cfg_data;
+ if (lut_cfg_data->version != mdp_hist_lut_v1_7 ||
+ !lut_cfg_data->cfg_payload) {
+ pr_err("invalid hist_lut version %d payload %p\n",
+ lut_cfg_data->version, lut_cfg_data->cfg_payload);
+ return -EINVAL;
+ }
+ if (!(lut_cfg_data->ops & ~(MDP_PP_OPS_READ))) {
+ pr_err("only read ops set for lut\n");
+ return ret;
+ }
+ if (!(lut_cfg_data->ops & MDP_PP_OPS_WRITE)) {
+ pr_debug("non write ops set %d\n", lut_cfg_data->ops);
+ goto bail_out;
+ }
+ lut_data = lut_cfg_data->cfg_payload;
+ if (lut_data->len != ENHIST_LUT_ENTRIES || !lut_data->data) {
+ pr_err("invalid hist_lut len %d data %p\n",
+ lut_data->len, lut_data->data);
+ return -EINVAL;
+ }
+ switch (block_type) {
+ case SSPP_VIG:
+ hist_addr = base_addr + REG_SSPP_VIG_HIST_LUT_BASE;
+ swap_addr = base_addr +
+ REG_SSPP_VIG_HIST_SWAP_BASE;
+ break;
+ case DSPP:
+ hist_addr = base_addr + REG_DSPP_HIST_LUT_BASE;
+ swap_addr = base_addr + REG_DSPP_HIST_SWAP_BASE;
+ break;
+ default:
+ pr_err("Invalid block type %d\n", block_type);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret) {
+ pr_err("hist_lut table not updated ret %d", ret);
+ return ret;
+ }
+ for (i = 0; i < ENHIST_LUT_ENTRIES; i += 2) {
+ temp = (lut_data->data[i] & ENHIST_LOWER_VALUE_MASK) |
+ ((lut_data->data[i + 1] & ENHIST_LOWER_VALUE_MASK)
+ << ENHIST_BIT_SHIFT);
+
+ writel_relaxed(temp, hist_addr);
+ hist_addr += 4;
+ }
+ if (lut_cfg_data->hist_lut_first)
+ pp_sts->enhist_sts |= PP_STS_PA_LUT_FIRST;
+
+
+ writel_relaxed(1, swap_addr);
+
+bail_out:
+ if (lut_cfg_data->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+ else if (lut_cfg_data->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->enhist_sts |= PP_STS_ENABLE;
+
+ return ret;
+}
+
static int pp_gamut_get_config(char __iomem *base_addr, void *cfg_data,
u32 block_type, u32 disp_num)
{
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index 8faaa3bc3a98..e37219d15f55 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -562,6 +562,11 @@ struct mdp_histogram_cfg {
uint16_t num_bins;
};
+enum {
+ mdp_hist_lut_v1_7 = 1,
+ mdp_hist_lut_vmax,
+};
+
struct mdp_hist_lut_data_v1_7 {
uint32_t len;
uint32_t *data;
@@ -570,6 +575,7 @@ struct mdp_hist_lut_data_v1_7 {
struct mdp_hist_lut_data {
uint32_t block;
uint32_t version;
+ uint32_t hist_lut_first;
uint32_t ops;
uint32_t len;
uint32_t *data;