Merge "msm: display: pp: backend dithering support"
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 7e21126..43cd86c 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1183,6 +1183,10 @@
break;
}
break;
+ case mdp_op_dither_cfg:
+ ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
+ ©back);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 9a5307c..c7d6939 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -306,6 +306,7 @@
int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index afd612f..afe2830 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -333,6 +333,7 @@
#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400))
#define MDSS_MDP_REG_DSPP_OP_MODE 0x000
#define MDSS_MDP_REG_DSPP_PCC_BASE 0x030
+#define MDSS_MDP_REG_DSPP_DITHER_DEPTH 0x150
#define MDSS_MDP_REG_DSPP_PA_BASE 0x238
#define MDSS_MDP_REG_DSPP_HIST_LUT_BASE 0x230
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 8cb64d4..d57c4b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -78,6 +78,12 @@
#define GC_LUT_SEGMENTS 16
#define ENHIST_LUT_ENTRIES 256
+static u32 dither_matrix[16] = {
+ 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10};
+static u32 dither_depth_map[9] = {
+ 0, 0, 0, 0, 0, 1, 2, 3, 3};
+
+
struct pp_sts_type {
u32 pa_sts;
u32 pcc_sts;
@@ -85,6 +91,7 @@
u32 igc_tbl_idx;
u32 argc_sts;
u32 enhist_sts;
+ u32 dither_sts;
};
#define PP_FLAGS_DIRTY_PA 0x1
@@ -92,6 +99,7 @@
#define PP_FLAGS_DIRTY_IGC 0x4
#define PP_FLAGS_DIRTY_ARGC 0x8
#define PP_FLAGS_DIRTY_ENHIST 0x10
+#define PP_FLAGS_DIRTY_DITHER 0x20
#define PP_STS_ENABLE 0x1
@@ -112,6 +120,7 @@
struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_pgc_lut_data pgc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_hist_lut_data enhist_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
/* physical info */
struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
};
@@ -266,8 +275,9 @@
struct mdp_pcc_cfg_data *pcc_config;
struct mdp_igc_lut_data *igc_config;
struct mdp_hist_lut_data *enhist_cfg;
+ struct mdp_dither_cfg_data *dither_cfg;
struct pp_sts_type *pp_sts;
- u32 tbl_idx;
+ u32 data, tbl_idx;
int i;
dspp_num = mixer->num;
/* no corresponding dspp */
@@ -369,7 +379,31 @@
MDSS_MDP_REG_WRITE(offset + 12, 0);
}
}
-
+ if (flags & PP_FLAGS_DIRTY_DITHER) {
+ dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
+ if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+ MDSS_MDP_REG_WRITE(offset,
+ dither_depth_map[dither_cfg->g_y_depth] |
+ (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
+ (dither_depth_map[dither_cfg->r_cr_depth] << 4));
+ offset += 0x14;
+ for (i = 0; i << 16; i += 4) {
+ data = dither_matrix[i] |
+ (dither_matrix[i + 1] << 4) |
+ (dither_matrix[i + 2] << 8) |
+ (dither_matrix[i + 3] << 12);
+ MDSS_MDP_REG_WRITE(offset, data);
+ offset += 4;
+ }
+ }
+ if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->dither_sts &= ~PP_STS_ENABLE;
+ else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->dither_sts |= PP_STS_ENABLE;
+ }
+ if (pp_sts->dither_sts & PP_STS_ENABLE)
+ opmode |= (1 << 8); /* DITHER_EN */
MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
return 0;
@@ -988,3 +1022,20 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
+
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+{
+ u32 disp_num;
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+ if (config->flags & MDP_PP_OPS_READ)
+ return -ENOTSUPP;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+ mdss_pp_res->dither_disp_cfg[disp_num] = *config;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
+ mutex_unlock(&mdss_pp_mutex);
+ return 0;
+}
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 800926b..863bb45 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -486,6 +486,14 @@
uint32_t cont_adj;
};
+struct mdp_dither_cfg_data {
+ uint32_t block;
+ uint32_t flags;
+ uint32_t g_y_depth;
+ uint32_t r_cr_depth;
+ uint32_t b_cb_depth;
+};
+
enum {
mdp_op_pcc_cfg,
mdp_op_csc_cfg,
@@ -493,6 +501,7 @@
mdp_op_qseed_cfg,
mdp_bl_scale_cfg,
mdp_op_pa_cfg,
+ mdp_op_dither_cfg,
mdp_op_max,
};
@@ -505,6 +514,7 @@
struct mdp_qseed_cfg_data qseed_cfg_data;
struct mdp_bl_scale_data bl_scale_data;
struct mdp_pa_cfg_data pa_cfg_data;
+ struct mdp_dither_cfg_data dither_cfg_data;
} data;
};