summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c268
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.h22
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c263
-rw-r--r--include/uapi/linux/msm_mdp.h155
4 files changed, 674 insertions, 34 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 6eb05b0e24c3..8069990cebd8 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
+#include <linux/vmalloc.h>
struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
[MDSS_MDP_CSC_RGB2RGB] = {
@@ -79,7 +80,6 @@ struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
#define CSC_LV_OFF 0x14
#define CSC_POST_OFF 0xC
-#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
#define HIST_INTR_DSPP_MASK 0xFFF000
#define HIST_V2_INTR_BIT_MASK 0xF33000
@@ -1602,6 +1602,12 @@ static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
if (side < 0)
return;
+ if (pp_driver_ops.pp_opmode_config) {
+ pp_driver_ops.pp_opmode_config(PP_OPMODE_DSPP,
+ pp_sts, opmode, side);
+ return;
+ }
+
if (pp_sts_is_enabled(pp_sts->pa_sts, side)) {
*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
pa_side_enabled = true;
@@ -1744,9 +1750,22 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
pp_dither_config(addr, pp_sts,
&mdss_pp_res->dither_disp_cfg[disp_num]);
}
- if (flags & PP_FLAGS_DIRTY_GAMUT)
- pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num], base,
- pp_sts);
+ if (flags & PP_FLAGS_DIRTY_GAMUT) {
+ if (!pp_ops[GAMUT].pp_set_config) {
+ pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num],
+ base, pp_sts);
+ } else {
+ if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) {
+ pr_err("invalid gamut off %d\n", U32_MAX);
+ } else {
+ addr = base +
+ mdata->pp_block_off.dspp_gamut_off;
+ pp_ops[GAMUT].pp_set_config(addr, pp_sts,
+ &mdss_pp_res->gamut_disp_cfg[disp_num],
+ DSPP);
+ }
+ }
+ }
if (flags & PP_FLAGS_DIRTY_PGC) {
pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
@@ -3317,15 +3336,190 @@ static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config)
return -EINVAL;
if (config->tbl_size[7] != GAMUT_T7_SIZE)
return -EINVAL;
-
return 0;
}
+static int pp_gamut_cache_params_v1_7(struct mdp_gamut_cfg_data *config)
+{
+ u32 disp_num, tbl_sz;
+ struct mdss_pp_res_type_v1_7 *res_cache;
+ struct mdp_gamut_data_v1_7 *v17_data, v17_config;
+ u32 gamut_size = 0, scal_coff_size = 0, sz = 0, index = 0;
+ u32 *tbl_gamut = NULL;
+ int ret = 0, i = 0;
+
+ if (!config) {
+ pr_err("invalid param config %p\n", config);
+ 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->flags & 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->gamut_disp_cfg[disp_num] = *config;
+ v17_data = &res_cache->gamut_v17_data[disp_num];
+ mdss_pp_res->gamut_disp_cfg[disp_num].cfg_payload =
+ (void *) v17_data;
+ tbl_gamut = v17_data->c0_data[0];
+
+ if (copy_from_user(&v17_config, config->cfg_payload,
+ sizeof(v17_config))) {
+ pr_err("failed to copy v17 gamut\n");
+ ret = -EFAULT;
+ goto gamut_config_exit;
+ }
+ if ((config->flags & MDP_PP_OPS_DISABLE)) {
+ pr_debug("disable gamut\n");
+ ret = 0;
+ goto gamut_memory_free_exit;
+ }
+ if (v17_config.mode != mdp_gamut_coarse_mode &&
+ v17_config.mode != mdp_gamut_fine_mode) {
+ pr_err("invalid gamut mode %d\n", v17_config.mode);
+ return -EINVAL;
+ }
+ if (!(config->flags & MDP_PP_OPS_WRITE)) {
+ pr_debug("op for gamut %d\n", config->flags);
+ goto gamut_config_exit;
+ }
+ tbl_sz = (v17_config.mode == mdp_gamut_fine_mode) ?
+ MDP_GAMUT_TABLE_V1_7_SZ :
+ MDP_GAMUT_TABLE_V1_7_COARSE_SZ;
+ memcpy(v17_data, &v17_config, sizeof(v17_config));
+
+ /* sanity check for sizes */
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ if (v17_config.tbl_size[i] != tbl_sz) {
+ pr_err("invalid tbl_sz %d exp %d for mode %d\n",
+ v17_config.tbl_size[i], tbl_sz,
+ v17_config.mode);
+ goto gamut_config_exit;
+ }
+ gamut_size += v17_config.tbl_size[i];
+ if (i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM)
+ continue;
+ if (v17_config.tbl_scale_off_sz[i] !=
+ MDP_GAMUT_SCALE_OFF_SZ) {
+ pr_err("invalid scale_sz %d exp %d for mode %d\n",
+ v17_config.tbl_scale_off_sz[i],
+ MDP_GAMUT_SCALE_OFF_SZ,
+ v17_config.mode);
+ goto gamut_config_exit;
+ }
+ scal_coff_size += v17_config.tbl_scale_off_sz[i];
+
+ }
+ /* gamut size should be accounted for c0, c1c2 table */
+ sz = gamut_size * 2 + scal_coff_size;
+ if (sz > GAMUT_TOTAL_TABLE_SIZE_V1_7) {
+ pr_err("Invalid table size act %d max %d\n",
+ sz, GAMUT_TOTAL_TABLE_SIZE_V1_7);
+ ret = -EINVAL;
+ goto gamut_config_exit;
+ }
+ /* Allocate for fine mode other modes will fit */
+ if (!tbl_gamut)
+ tbl_gamut = vmalloc(GAMUT_TOTAL_TABLE_SIZE_V1_7 *
+ sizeof(u32));
+ if (!tbl_gamut) {
+ pr_err("failed to allocate buffer for gamut size %zd",
+ (GAMUT_TOTAL_TABLE_SIZE_V1_7 * sizeof(u32)));
+ ret = -ENOMEM;
+ goto gamut_config_exit;
+ }
+ index = 0;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ ret = copy_from_user(&tbl_gamut[index],
+ v17_config.c0_data[i],
+ (sizeof(u32) * v17_config.tbl_size[i]));
+ if (ret) {
+ pr_err("copying c0 table %d from userspace failed size %zd ret %d\n",
+ i, (sizeof(u32) *
+ v17_config.tbl_size[i]), ret);
+ ret = -EINVAL;
+ goto gamut_memory_free_exit;
+ }
+ v17_data->c0_data[i] = &tbl_gamut[index];
+ index += v17_config.tbl_size[i];
+ ret = copy_from_user(&tbl_gamut[index],
+ v17_config.c1_c2_data[i],
+ (sizeof(u32) * v17_config.tbl_size[i]));
+ if (ret) {
+ pr_err("copying c1_c2 table %d from userspace failed size %zd ret %d\n",
+ i, (sizeof(u32) *
+ v17_config.tbl_size[i]), ret);
+ ret = -EINVAL;
+ goto gamut_memory_free_exit;
+ }
+ v17_data->c1_c2_data[i] = &tbl_gamut[index];
+ index += v17_config.tbl_size[i];
+ }
+ for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) {
+ ret = copy_from_user(&tbl_gamut[index],
+ v17_config.scale_off_data[i],
+ (sizeof(u32) *
+ v17_config.tbl_scale_off_sz[i]));
+ if (ret) {
+ pr_err("copying scale offset table %d from userspace failed size %zd ret %d\n",
+ i, (sizeof(u32) *
+ v17_config.tbl_scale_off_sz[i]), ret);
+ ret = -EINVAL;
+ goto gamut_memory_free_exit;
+ }
+ v17_data->scale_off_data[i] = &tbl_gamut[index];
+ index += v17_config.tbl_scale_off_sz[i];
+ }
+ }
+gamut_config_exit:
+ return ret;
+gamut_memory_free_exit:
+ vfree(tbl_gamut);
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ v17_data->c0_data[i] = NULL;
+ v17_data->c1_c2_data[i] = NULL;
+ if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM)
+ v17_data->scale_off_data[i] = NULL;
+ }
+ return ret;
+}
+
+static int pp_gamut_cache_params(struct mdp_gamut_cfg_data *config)
+{
+ int ret = 0;
+ if (!config) {
+ pr_err("invalid param config %p\n", config);
+ return -EINVAL;
+ }
+ switch (config->version) {
+ case mdp_gamut_v1_7:
+ ret = pp_gamut_cache_params_v1_7(config);
+ break;
+ default:
+ pr_err("unsupported gamut version %d\n",
+ config->version);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
u32 *copyback)
{
int i, j, ret = 0;
-
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
@@ -3339,9 +3533,6 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
- if (pp_gm_has_invalid_lut_size(config))
- return -EINVAL;
-
if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
pr_warn("Can't set both split bits\n");
return -EINVAL;
@@ -3358,7 +3549,32 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
goto gamut_config_exit;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
-
+ if (pp_ops[GAMUT].pp_get_config) {
+ addr = mdss_mdp_get_dspp_addr_off(disp_num);
+ if (IS_ERR_OR_NULL(addr)) {
+ pr_err("invalid dspp base addr %p\n",
+ addr);
+ ret = -EINVAL;
+ goto gamut_clk_off;
+ }
+ if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) {
+ pr_err("invalid gamut parmas off %d\n",
+ mdata->pp_block_off.dspp_gamut_off);
+ ret = -EINVAL;
+ goto gamut_clk_off;
+ }
+ addr += mdata->pp_block_off.dspp_gamut_off;
+ ret = pp_ops[GAMUT].pp_get_config(addr, config, DSPP,
+ disp_num);
+ if (ret)
+ pr_err("gamut get config failed %d\n", ret);
+ goto gamut_clk_off;
+ }
+ if (pp_gm_has_invalid_lut_size(config)) {
+ pr_err("invalid lut size for gamut\n");
+ ret = -EINVAL;
+ goto gamut_clk_off;
+ }
addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_GAMUT_BASE;
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
@@ -3367,7 +3583,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
GFP_KERNEL);
if (!r_tbl[i]) {
pr_err("%s: alloc failed\n", __func__);
- goto gamut_config_exit;
+ ret = -ENOMEM;
+ goto gamut_clk_off;
}
/* Reset gamut LUT index to 0 */
writel_relaxed(data, addr);
@@ -3380,7 +3597,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
if (ret) {
pr_err("%s: copy tbl to usr failed\n",
__func__);
- goto gamut_config_exit;
+ ret = -EFAULT;
+ goto gamut_clk_off;
}
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
@@ -3389,7 +3607,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
GFP_KERNEL);
if (!g_tbl[i]) {
pr_err("%s: alloc failed\n", __func__);
- goto gamut_config_exit;
+ ret = -ENOMEM;
+ goto gamut_clk_off;
}
/* Reset gamut LUT index to 0 */
writel_relaxed(data, addr);
@@ -3402,7 +3621,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
if (ret) {
pr_err("%s: copy tbl to usr failed\n",
__func__);
- goto gamut_config_exit;
+ ret = -EFAULT;
+ goto gamut_clk_off;
}
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
@@ -3411,7 +3631,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
GFP_KERNEL);
if (!b_tbl[i]) {
pr_err("%s: alloc failed\n", __func__);
- goto gamut_config_exit;
+ ret = -ENOMEM;
+ goto gamut_clk_off;
}
/* Reset gamut LUT index to 0 */
writel_relaxed(data, addr);
@@ -3424,12 +3645,26 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
if (ret) {
pr_err("%s: copy tbl to usr failed\n",
__func__);
- goto gamut_config_exit;
+ ret = -EFAULT;
+ goto gamut_clk_off;
}
}
*copyback = 1;
+gamut_clk_off:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
} else {
+ if (pp_ops[GAMUT].pp_set_config) {
+ pr_debug("version of gamut is %d\n", config->version);
+ ret = pp_gamut_cache_params(config);
+ if (ret) {
+ pr_err("gamut config failed version %d ret %d\n",
+ config->version, ret);
+ ret = -EFAULT;
+ goto gamut_config_exit;
+ } else {
+ goto gamut_set_dirty;
+ }
+ }
local_cfg = *config;
tbl_off = mdss_pp_res->gamut_tbl[disp_num];
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
@@ -3460,6 +3695,7 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
tbl_off += local_cfg.tbl_size[i];
}
mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg;
+gamut_set_dirty:
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT;
}
gamut_config_exit:
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h
index d18fbd49b135..a5d970af5e0c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h
@@ -17,6 +17,8 @@
#include <linux/msm_mdp.h>
+#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
+
/* PP STS related flags */
#define PP_STS_ENABLE 0x1
@@ -24,6 +26,12 @@
#define MDSS_SIDE_NONE 0
#define MDSS_SIDE_LEFT 1
#define MDSS_SIDE_RIGHT 2
+/* size calculated for c0,c1_c2 for 4 tables */
+#define GAMUT_COLOR_COEFF_SIZE_V1_7 (2 * MDP_GAMUT_TABLE_V1_7_SZ * 4)
+/* 16 entries for c0,c1,c2 */
+#define GAMUT_SCALE_OFFSET_SIZE_V1_7 (3 * MDP_GAMUT_SCALE_OFF_SZ)
+#define GAMUT_TOTAL_TABLE_SIZE_V1_7 (GAMUT_COLOR_COEFF_SIZE_V1_7 + \
+ GAMUT_SCALE_OFFSET_SIZE_V1_7)
/* PP Feature Operations */
enum pp_features {
@@ -40,11 +48,19 @@ enum pp_features {
};
enum pp_block_opmodes {
- PP_OPMODE_VIG,
+ PP_OPMODE_VIG = 1,
PP_OPMODE_DSPP,
PP_OPMODE_MAX
};
+enum pp_config_block {
+ SSPP_RGB = 1,
+ SSPP_DMA,
+ SSPP_VIG,
+ DSPP,
+ LM
+};
+
struct mdp_pp_feature_ops {
u32 feature;
int (*pp_get_config)(char __iomem *base_addr, void *cfg_data,
@@ -60,6 +76,10 @@ struct mdp_pp_driver_ops {
u32 *opmode, int side);
};
+struct mdss_pp_res_type_v1_7 {
+ struct mdp_gamut_data_v1_7 gamut_v17_data[MDSS_BLOCK_DISP_NUM];
+};
+
#ifdef CONFIG_ARCH_MSMTHULIUM
void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops);
#else
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 35e7b0da6e55..850233cb491d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
@@ -22,6 +22,28 @@
static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
u32 *opmode, int side);
+#define GAMUT_OP_MODE_OFF 0
+#define GAMUT_TABLE_INDEX 4
+#define GAMUT_TABLE_UPPER_R 8
+#define GAMUT_TABLE_LOWER_GB 0xC
+#define GAMUT_C0_SCALE_OFF 0x10
+#define GAMUT_CLK_CTRL 0xD0
+#define GAMUT_CLK_STATUS 0xD4
+#define GAMUT_READ_TABLE_EN BIT(16)
+#define GAMUT_TABLE_SELECT(x) ((BIT(x)) << 12)
+#define GAMUT_COARSE_EN (BIT(2))
+#define GAMUT_COARSE_INDEX 1248
+#define GAMUT_FINE_INDEX 0
+#define GAMUT_ENABLE BIT(0)
+
+static struct mdss_pp_res_type_v1_7 config_data;
+
+static int pp_gamut_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num);
+static int pp_gamut_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
+
void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
{
if (!ops) {
@@ -46,8 +68,8 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
ops->pp_ops[PA].pp_get_config = NULL;
/* Gamut ops */
- ops->pp_ops[GAMUT].pp_set_config = NULL;
- ops->pp_ops[GAMUT].pp_get_config = NULL;
+ ops->pp_ops[GAMUT].pp_set_config = pp_gamut_set_config;
+ ops->pp_ops[GAMUT].pp_get_config = pp_gamut_get_config;
/* CSC ops */
ops->pp_ops[CSC].pp_set_config = NULL;
@@ -68,7 +90,7 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
/* Set opmode pointers */
ops->pp_opmode_config = pp_opmode_config;
- return NULL;
+ return &config_data;
}
static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
@@ -81,3 +103,238 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
return;
}
+
+static int pp_gamut_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num)
+{
+ u32 val = 0, sz = 0, sz_scale = 0, mode = 0, tbl_sz = 0;
+ u32 index_start = 0;
+ int i = 0, j = 0, ret = 0;
+ u32 *gamut_tbl = NULL, *gamut_c0 = NULL, *gamut_c1c2 = NULL;
+ struct mdp_gamut_cfg_data *gamut_cfg = (struct mdp_gamut_cfg_data *)
+ cfg_data;
+ struct mdp_gamut_data_v1_7 gamut_data;
+
+ if (!base_addr || !cfg_data) {
+ pr_err("invalid params base_addr %p cfg_data %p\n",
+ base_addr, cfg_data);
+ return -EINVAL;
+ }
+ if (gamut_cfg->version != mdp_gamut_v1_7) {
+ pr_err("unsupported version of gamut %d\n",
+ gamut_cfg->version);
+ return -EINVAL;
+ }
+ if (copy_from_user(&gamut_data, gamut_cfg->cfg_payload,
+ sizeof(gamut_data))) {
+ pr_err("copy from user failed for gamut_data\n");
+ return -EFAULT;
+ }
+ mode = readl_relaxed(base_addr + GAMUT_OP_MODE_OFF);
+ if (mode & GAMUT_COARSE_EN) {
+ tbl_sz = MDP_GAMUT_TABLE_V1_7_COARSE_SZ;
+ sz = tbl_sz * sizeof(u32);
+ index_start = GAMUT_COARSE_INDEX;
+ } else {
+ mode = mdp_gamut_fine_mode;
+ tbl_sz = MDP_GAMUT_TABLE_V1_7_SZ;
+ sz = tbl_sz * sizeof(u32);
+ index_start = GAMUT_FINE_INDEX;
+ }
+ sz_scale = MDP_GAMUT_SCALE_OFF_SZ * sizeof(u32);
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ if (!access_ok(VERIFY_WRITE, gamut_data.c0_data[i], sz)) {
+ pr_err("invalid c0 address for sz %d table index %d\n",
+ sz, (i+1));
+ return -EFAULT;
+ }
+ if (!access_ok(VERIFY_WRITE, gamut_data.c1_c2_data[i], sz)) {
+ pr_err("invalid c1c2 address for sz %d table index %d\n",
+ sz, (i+1));
+ return -EFAULT;
+ }
+ gamut_data.tbl_size[i] = tbl_sz;
+ if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM) {
+ if (!access_ok(VERIFY_WRITE,
+ gamut_data.scale_off_data[i], sz_scale)) {
+ pr_err("invalid scale address for sz %d color c%d\n",
+ sz_scale, i);
+ return -EFAULT;
+ }
+ gamut_data.tbl_scale_off_sz[i] =
+ MDP_GAMUT_SCALE_OFF_SZ;
+ }
+ }
+ /* allocate for c0 and c1c2 tables */
+ gamut_tbl = kzalloc((sz * 2) , GFP_KERNEL);
+ if (!gamut_tbl) {
+ pr_err("failed to alloc table of sz %d\n", sz);
+ return -ENOMEM;
+ }
+ gamut_c0 = gamut_tbl;
+ gamut_c1c2 = gamut_c0 + tbl_sz;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ val = index_start;
+ val |= GAMUT_READ_TABLE_EN;
+ val |= GAMUT_TABLE_SELECT(i);
+ writel_relaxed(val, (base_addr + GAMUT_TABLE_INDEX));
+ for (j = 0; j < tbl_sz; j++) {
+ gamut_c1c2[j] = readl_relaxed(base_addr +
+ GAMUT_TABLE_LOWER_GB);
+ gamut_c0[j] = readl_relaxed(base_addr +
+ GAMUT_TABLE_UPPER_R);
+ }
+ if (copy_to_user(gamut_data.c0_data[i], gamut_c0, sz)) {
+ pr_err("copy to user failed for table %d c0 sz %d\n",
+ (i + 1), sz);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ if (copy_to_user(gamut_data.c1_c2_data[i], gamut_c1c2, sz)) {
+ pr_err("copy to user failed for table %d c1c2 sz %d\n",
+ (i + 1), sz);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ }
+ sz_scale = MDP_GAMUT_SCALE_OFF_TABLE_NUM * MDP_GAMUT_SCALE_OFF_SZ
+ * sizeof(u32);
+ if (sz < sz_scale) {
+ kfree(gamut_tbl);
+ gamut_tbl = kzalloc(sz_scale , GFP_KERNEL);
+ if (!gamut_tbl) {
+ pr_err("failed to alloc scale tbl size %d\n",
+ sz_scale);
+ ret = -ENOMEM;
+ goto bail_out;
+ }
+ }
+ gamut_c0 = gamut_tbl;
+ base_addr += GAMUT_C0_SCALE_OFF;
+ for (i = 0;
+ i < (MDP_GAMUT_SCALE_OFF_TABLE_NUM * MDP_GAMUT_SCALE_OFF_SZ);
+ i++) {
+ gamut_c0[i] = readl_relaxed(base_addr);
+ base_addr += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) {
+ if (copy_to_user(gamut_data.scale_off_data[i],
+ &gamut_c0[i * MDP_GAMUT_SCALE_OFF_SZ],
+ (MDP_GAMUT_SCALE_OFF_SZ * sizeof(u32)))) {
+ pr_err("copy to user failed for scale color c%d\n",
+ i);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ }
+ if (copy_to_user(gamut_cfg->cfg_payload, &gamut_data,
+ sizeof(gamut_data))) {
+ pr_err("failed to copy the gamut info into payload\n");
+ ret = -EFAULT;
+ }
+bail_out:
+ kfree(gamut_tbl);
+ return ret;
+}
+
+static int pp_gamut_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type)
+{
+ int val = 0, ret = 0, i = 0, j = 0;
+ u32 index_start = 0, tbl_sz = 0;
+ struct mdp_gamut_cfg_data *gamut_cfg_data = NULL;
+ struct mdp_gamut_data_v1_7 *gamut_data = NULL;
+ char __iomem *base_addr_scale = base_addr;
+ 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;
+ }
+ gamut_cfg_data = (struct mdp_gamut_cfg_data *) cfg_data;
+ if (gamut_cfg_data->version != mdp_gamut_v1_7) {
+ pr_err("invalid gamut version %d\n", gamut_cfg_data->version);
+ return -EINVAL;
+ }
+ if (!(gamut_cfg_data->flags & ~(MDP_PP_OPS_READ))) {
+ pr_info("only read ops is set %d", gamut_cfg_data->flags);
+ return 0;
+ }
+ gamut_data = gamut_cfg_data->cfg_payload;
+ if (!gamut_data) {
+ pr_err("invalid payload for gamut %p\n", gamut_data);
+ return -EINVAL;
+ }
+
+ if (gamut_data->mode != mdp_gamut_fine_mode &&
+ gamut_data->mode != mdp_gamut_coarse_mode) {
+ pr_err("invalid gamut mode %d", gamut_data->mode);
+ return -EINVAL;
+ }
+ index_start = (gamut_data->mode == mdp_gamut_fine_mode) ?
+ GAMUT_FINE_INDEX : GAMUT_COARSE_INDEX;
+ tbl_sz = (gamut_data->mode == mdp_gamut_fine_mode) ?
+ MDP_GAMUT_TABLE_V1_7_SZ : MDP_GAMUT_TABLE_V1_7_COARSE_SZ;
+ if (!(gamut_cfg_data->flags & MDP_PP_OPS_WRITE))
+ goto bail_out;
+ /* Sanity check for all tables */
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ if (!gamut_data->c0_data[i] || !gamut_data->c1_c2_data[i]
+ || (gamut_data->tbl_size[i] != tbl_sz)) {
+ pr_err("invalid param for c0 %p c1c2 %p table %d size %d expected sz %d\n",
+ gamut_data->c0_data[i],
+ gamut_data->c1_c2_data[i], (i + 1),
+ gamut_data->tbl_size[i], tbl_sz);
+ ret = -EINVAL;
+ goto bail_out;
+ }
+ if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM &&
+ (!gamut_data->scale_off_data[i] ||
+ (gamut_data->tbl_scale_off_sz[i] !=
+ MDP_GAMUT_SCALE_OFF_SZ))) {
+ pr_err("invalid param for scale table %p for c%d size %d expected size%d\n",
+ gamut_data->scale_off_data[i], i,
+ gamut_data->tbl_scale_off_sz[i],
+ MDP_GAMUT_SCALE_OFF_SZ);
+ ret = -EINVAL;
+ goto bail_out;
+ }
+ }
+ base_addr_scale += GAMUT_C0_SCALE_OFF;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
+ val = index_start;
+ val |= GAMUT_TABLE_SELECT(i);
+ writel_relaxed(val, (base_addr + GAMUT_TABLE_INDEX));
+ for (j = 0; j < gamut_data->tbl_size[i]; j++) {
+ writel_relaxed(gamut_data->c1_c2_data[i][j],
+ base_addr + GAMUT_TABLE_LOWER_GB);
+ writel_relaxed(gamut_data->c0_data[i][j],
+ base_addr + GAMUT_TABLE_UPPER_R);
+ }
+ if (i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM)
+ continue;
+ for (j = 0; j < MDP_GAMUT_SCALE_OFF_SZ; j++) {
+ writel_relaxed((gamut_data->scale_off_data[i][j]),
+ base_addr_scale);
+ base_addr_scale += 4;
+ }
+ }
+bail_out:
+ if (!ret) {
+ val = 0;
+ if (gamut_cfg_data->flags & MDP_PP_OPS_DISABLE) {
+ pp_sts->gamut_sts &= ~PP_STS_ENABLE;
+ writel_relaxed(val, base_addr + GAMUT_OP_MODE_OFF);
+ } else if (gamut_cfg_data->flags & MDP_PP_OPS_ENABLE) {
+ if (gamut_data->mode == mdp_gamut_coarse_mode)
+ val |= GAMUT_COARSE_EN;
+ val |= GAMUT_ENABLE;
+ writel_relaxed(val, base_addr + GAMUT_OP_MODE_OFF);
+ pp_sts->gamut_sts |= PP_STS_ENABLE;
+ }
+ pp_sts_set_split_bits(&pp_sts->gamut_sts,
+ gamut_cfg_data->flags);
+ }
+ return ret;
+}
+
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index 335bcc082e46..7eba5283018d 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -307,6 +307,7 @@ struct mdp_blit_req {
uint32_t transp_mask;
uint32_t flags;
int sharpening_strength; /* -127 <--> 127, default 64 */
+ uint8_t color_space;
};
struct mdp_blit_req_list {
@@ -426,19 +427,34 @@ struct mdp_qseed_cfg_data {
#define MDP_CSC_FLAG_YUV_IN 0x2
#define MDP_CSC_FLAG_YUV_OUT 0x4
+#define MDP_CSC_MATRIX_COEFF_SIZE 9
+#define MDP_CSC_CLAMP_SIZE 6
+#define MDP_CSC_BIAS_SIZE 3
+
struct mdp_csc_cfg {
/* flags for enable CSC, toggling RGB,YUV input/output */
uint32_t flags;
- uint32_t csc_mv[9];
- uint32_t csc_pre_bv[3];
- uint32_t csc_post_bv[3];
- uint32_t csc_pre_lv[6];
- uint32_t csc_post_lv[6];
+ uint32_t csc_mv[MDP_CSC_MATRIX_COEFF_SIZE];
+ uint32_t csc_pre_bv[MDP_CSC_BIAS_SIZE];
+ uint32_t csc_post_bv[MDP_CSC_BIAS_SIZE];
+ uint32_t csc_pre_lv[MDP_CSC_CLAMP_SIZE];
+ uint32_t csc_post_lv[MDP_CSC_CLAMP_SIZE];
+};
+
+struct mdp_csc_cfg_v1_7 {
+ uint32_t csc_mv[MDP_CSC_MATRIX_COEFF_SIZE];
+ uint32_t csc_pre_bv[MDP_CSC_BIAS_SIZE];
+ uint32_t csc_post_bv[MDP_CSC_BIAS_SIZE];
+ uint32_t csc_pre_lv[MDP_CSC_CLAMP_SIZE];
+ uint32_t csc_post_lv[MDP_CSC_CLAMP_SIZE];
};
struct mdp_csc_cfg_data {
uint32_t block;
+ uint32_t version;
+ uint32_t flags;
struct mdp_csc_cfg csc_data;
+ void *cfg_payload;
};
struct mdp_pa_cfg {
@@ -457,6 +473,16 @@ struct mdp_pa_mem_col_cfg {
uint32_t val_region;
};
+struct mdp_pa_mem_col_cfg_v1_7 {
+ uint32_t color_adjust_p0;
+ uint32_t color_adjust_p1;
+ uint32_t color_adjust_p2;
+ uint32_t blend_gain;
+ uint32_t hue_region;
+ uint32_t sat_region;
+ uint32_t val_region;
+};
+
#define MDP_SIX_ZONE_LUT_SIZE 384
struct mdp_pa_v2_data {
@@ -466,20 +492,53 @@ struct mdp_pa_v2_data {
uint32_t global_sat_adj;
uint32_t global_val_adj;
uint32_t global_cont_adj;
+ struct mdp_pa_mem_col_cfg skin_cfg;
+ struct mdp_pa_mem_col_cfg sky_cfg;
+ struct mdp_pa_mem_col_cfg fol_cfg;
uint32_t six_zone_len;
+ uint32_t six_zone_thresh;
uint32_t *six_zone_curve_p0;
uint32_t *six_zone_curve_p1;
+};
+
+struct mdp_pa_data_v1_7 {
+ uint32_t global_hue_adj;
+ uint32_t global_sat_adj;
+ uint32_t global_val_adj;
+ uint32_t global_cont_adj;
+ struct mdp_pa_mem_col_cfg_v1_7 skin_cfg;
+ struct mdp_pa_mem_col_cfg_v1_7 sky_cfg;
+ struct mdp_pa_mem_col_cfg_v1_7 fol_cfg;
+ uint32_t six_zone_len;
uint32_t six_zone_thresh;
- struct mdp_pa_mem_col_cfg skin_cfg;
- struct mdp_pa_mem_col_cfg sky_cfg;
- struct mdp_pa_mem_col_cfg fol_cfg;
+ uint32_t six_zone_adj_p0;
+ uint32_t six_zone_adj_p1;
+ uint32_t *six_zone_curve_p0;
+ uint32_t *six_zone_curve_p1;
+};
+
+struct mdp_pa_v2_cfg_data {
+ uint32_t version;
+ uint32_t block;
+ uint32_t flags;
+ uint32_t mode;
+ struct mdp_pa_v2_data pa_v2_data;
+ void *cfg_payload;
};
struct mdp_igc_lut_data {
uint32_t block;
+ uint32_t version;
uint32_t len, ops;
uint32_t *c0_c1_data;
uint32_t *c2_data;
+ void *cfg_payload;
+};
+
+struct mdp_igc_lut_data_v1_7 {
+ uint32_t len;
+ uint32_t *c0_c1_data;
+ uint32_t *c2_data;
};
struct mdp_histogram_cfg {
@@ -490,11 +549,18 @@ struct mdp_histogram_cfg {
uint16_t num_bins;
};
+struct mdp_hist_lut_data_v1_7 {
+ uint32_t len;
+ uint32_t *data;
+};
+
struct mdp_hist_lut_data {
uint32_t block;
+ uint32_t version;
uint32_t ops;
uint32_t len;
uint32_t *data;
+ void *cfg_payload;
};
struct mdp_overlay_pp_params {
@@ -651,6 +717,7 @@ struct mdp_overlay {
uint8_t vert_deci;
struct mdp_overlay_pp_params overlay_pp_cfg;
struct mdp_scale_data scale;
+ uint8_t color_space;
};
struct msmfb_overlay_3d {
@@ -765,14 +832,22 @@ struct mdp_pcc_coeff {
uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1;
};
+struct mdp_pcc_coeff_v1_7 {
+ uint32_t c, r, g, b, rg, gb, rb, rgb;
+};
+
+struct mdp_pcc_data_v1_7 {
+ struct mdp_pcc_coeff_v1_7 r, g, b;
+};
+
struct mdp_pcc_cfg_data {
+ uint32_t version;
uint32_t block;
uint32_t ops;
struct mdp_pcc_coeff r, g, b;
+ void *cfg_payload;
};
-#define MDP_GAMUT_TABLE_NUM 8
-
enum {
mdp_lut_igc,
mdp_lut_pgc,
@@ -780,6 +855,8 @@ enum {
mdp_lut_max,
};
+#define GC_LUT_ENTRIES_V1_7 512
+
struct mdp_ar_gc_lut_data {
uint32_t x_start;
uint32_t slope;
@@ -787,6 +864,7 @@ struct mdp_ar_gc_lut_data {
};
struct mdp_pgc_lut_data {
+ uint32_t version;
uint32_t block;
uint32_t flags;
uint8_t num_r_stages;
@@ -795,8 +873,15 @@ struct mdp_pgc_lut_data {
struct mdp_ar_gc_lut_data *r_data;
struct mdp_ar_gc_lut_data *g_data;
struct mdp_ar_gc_lut_data *b_data;
+ void *cfg_payload;
};
+struct mdp_pgc_lut_data_v1_7 {
+ uint32_t len;
+ uint32_t *c0_data;
+ uint32_t *c1_data;
+ uint32_t *c2_data;
+};
struct mdp_lut_cfg_data {
uint32_t lut_type;
@@ -817,27 +902,62 @@ struct mdp_pa_cfg_data {
struct mdp_pa_cfg pa_data;
};
-struct mdp_pa_v2_cfg_data {
- uint32_t block;
- struct mdp_pa_v2_data pa_v2_data;
+struct mdp_dither_data_v1_7 {
+ uint32_t g_y_depth;
+ uint32_t r_cr_depth;
+ uint32_t b_cb_depth;
};
struct mdp_dither_cfg_data {
+ uint32_t version;
uint32_t block;
uint32_t flags;
+ uint32_t mode;
uint32_t g_y_depth;
uint32_t r_cr_depth;
uint32_t b_cb_depth;
+ void *cfg_payload;
+};
+
+#define MDP_GAMUT_TABLE_NUM 8
+#define MDP_GAMUT_TABLE_NUM_V1_7 4
+#define MDP_GAMUT_SCALE_OFF_TABLE_NUM 3
+#define MDP_GAMUT_TABLE_V1_7_SZ 1228
+#define MDP_GAMUT_SCALE_OFF_SZ 16
+#define MDP_GAMUT_TABLE_V1_7_COARSE_SZ 32
+
+enum {
+ mdp_gamut_v1_7 = 1,
+ mdp_gamut_vmax,
};
+
struct mdp_gamut_cfg_data {
uint32_t block;
uint32_t flags;
+ uint32_t version;
+ /* v1 version specific params */
uint32_t gamut_first;
uint32_t tbl_size[MDP_GAMUT_TABLE_NUM];
uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+ /* params for newer versions of gamut */
+ void *cfg_payload;
+};
+
+enum {
+ mdp_gamut_fine_mode = 0x1,
+ mdp_gamut_coarse_mode,
+};
+
+struct mdp_gamut_data_v1_7 {
+ uint32_t mode;
+ uint32_t tbl_size[MDP_GAMUT_TABLE_NUM_V1_7];
+ uint32_t *c0_data[MDP_GAMUT_TABLE_NUM_V1_7];
+ uint32_t *c1_c2_data[MDP_GAMUT_TABLE_NUM_V1_7];
+ uint32_t tbl_scale_off_sz[MDP_GAMUT_SCALE_OFF_TABLE_NUM];
+ uint32_t *scale_off_data[MDP_GAMUT_SCALE_OFF_TABLE_NUM];
};
struct mdp_calib_config_data {
@@ -1008,6 +1128,7 @@ struct msmfb_mdp_pp {
struct mdp_gamut_cfg_data gamut_cfg_data;
struct mdp_calib_config_data calib_cfg;
struct mdss_ad_init_cfg ad_init_cfg;
+ struct mdss_calib_cfg mdss_calib_cfg;
struct mdss_ad_input ad_input;
struct mdp_calib_config_buffer calib_buffer;
struct mdp_calib_dcm_state calib_dcm;
@@ -1063,7 +1184,7 @@ struct msmfb_metadata {
} data;
};
-#define MDP_MAX_FENCE_FD 10
+#define MDP_MAX_FENCE_FD 32
#define MDP_BUF_SYNC_FLAG_WAIT 1
#define MDP_BUF_SYNC_FLAG_RETIRE_FENCE 0x10
@@ -1147,4 +1268,10 @@ enum {
MDP_WRITEBACK_MIRROR_PAUSE,
MDP_WRITEBACK_MIRROR_RESUME,
};
+
+enum {
+ MDP_CSC_ITU_R_601,
+ MDP_CSC_ITU_R_601_FR,
+ MDP_CSC_ITU_R_709,
+};
#endif /*_UAPI_MSM_MDP_H_*/