diff options
| author | Ken Zhang <kenz@codeaurora.org> | 2012-08-10 11:27:19 -0400 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:12:22 -0700 |
| commit | 8a2c7f8bc367bf4119606032543efa5a2bcf267b (patch) | |
| tree | 2bbb42ab888e365700035988aef58c6c0a10b661 /drivers/video/fbdev | |
| parent | 89d600ec483b93a159b097f5576756c6794fb44d (diff) | |
mdss: display: postprocessing: picture adjustment
Support picture adjustment(hue, sat) for 8974
Use logical block id as input. Apply configuration
at next display commit.
kernel 3.14 upgrade conflicts:
include/uapi/linux/msm_mdp.h
Change-Id: I0e35e50aecdd346ec91373d0c304e21185f28502
Signed-off-by: Ken Zhang <kenz@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 29 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.c | 10 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 32 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_hwio.h | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 163 |
6 files changed, 235 insertions, 10 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 3d09f597f588..cd0848863cde 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1137,6 +1137,31 @@ static int mdss_fb_set_lut(struct fb_info *info, void __user *p) return 0; } +static int mdss_fb_handle_pp_ioctl(void __user *argp) +{ + int ret; + struct msmfb_mdp_pp mdp_pp; + u32 copyback = 0; + + ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp)); + if (ret) + return ret; + + switch (mdp_pp.op) { + case mdp_op_pa_cfg: + ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data, + ©back); + break; + default: + pr_err("Unsupported request to MDP_PP IOCTL.\n"); + ret = -EINVAL; + break; + } + if ((ret == 0) && copyback) + ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp)); + return ret; +} + static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -1163,6 +1188,10 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, return ret; break; + case MSMFB_MDP_PP: + ret = mdss_fb_handle_pp_ioctl(argp); + break; + default: if (mfd->ioctl_handler) ret = mfd->ioctl_handler(mfd, cmd, argp); diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index acc0b8f9db19..e3371363c38f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -846,10 +846,17 @@ static int mdss_mdp_probe(struct platform_device *pdev) pr_err("unable to initialize mdss mdp resources\n"); goto probe_done; } + rc = mdss_mdp_pp_init(&pdev->dev); + if (rc) { + pr_err("unable to initialize mdss pp resources\n"); + goto probe_done; + } rc = mdss_mdp_bus_scale_register(mdata); probe_done: - if (IS_ERR_VALUE(rc)) + if (IS_ERR_VALUE(rc)) { mdss_res = NULL; + mdss_mdp_pp_term(&pdev->dev); + } return rc; } @@ -946,6 +953,7 @@ static int mdss_mdp_remove(struct platform_device *pdev) if (!mdata) return -ENODEV; pm_runtime_disable(&pdev->dev); + mdss_mdp_pp_term(&pdev->dev); mdss_mdp_bus_scale_unregister(mdata); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index c0ac12229a11..afdfb1318a43 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -295,7 +295,7 @@ int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe); int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg); int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type); -int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer); +int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type); @@ -318,4 +318,9 @@ int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data); int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl); int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg); +int mdss_mdp_pp_init(struct device *dev); +void mdss_mdp_pp_term(struct device *dev); +int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback); + +int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id); #endif /* MDSS_MDP_H */ diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index a1606967ab33..9000bcf4f9d7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -807,9 +807,6 @@ static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer) { mixer->params_changed = 0; - if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) - mdss_mdp_dspp_setup(mixer->ctl, mixer); - /* skip mixer setup for rotator */ if (!mixer->rotator_mode) mdss_mdp_mixer_setup(mixer->ctl, mixer); @@ -863,6 +860,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg) ctl->flush_bits |= BIT(17); /* CTL */ } + /* postprocessing setup, including dspp */ + mdss_mdp_pp_setup(ctl); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits); wmb(); ctl->flush_bits = 0; @@ -884,3 +883,30 @@ done: return ret; } + +int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id) +{ + int i; + struct mdss_mdp_ctl *ctl; + u32 mixer_cnt = 0; + mutex_lock(&mdss_mdp_ctl_lock); + for (i = 0; i < MDSS_MDP_MAX_CTL; i++) { + ctl = &mdss_mdp_ctl_list[i]; + if ((ctl->power_on) && + (ctl->mfd->index == fb_num)) { + if (ctl->mixer_left) { + mixer_id[mixer_cnt] = ctl->mixer_left->num; + mixer_cnt++; + } + if (mixer_cnt && ctl->mixer_right) { + mixer_id[mixer_cnt] = ctl->mixer_right->num; + mixer_cnt++; + } + if (mixer_cnt) + break; + } + } + mutex_unlock(&mdss_mdp_ctl_lock); + return mixer_cnt; +} + diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index d013a4f8e724..7fcee5e87768 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -321,6 +321,10 @@ enum mdss_mdp_dspp_index { MDSS_MDP_MAX_DSPP }; +#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400)) +#define MDSS_MDP_REG_DSPP_OP_MODE 0x000 +#define MDSS_MDP_REG_DSPP_PA_BASE 0x238 + enum mdss_mpd_intf_index { MDSS_MDP_NO_INTF, MDSS_MDP_INTF0, diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index b84a0750420e..70eb6352d7dc 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -13,6 +13,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ +#include "mdss_fb.h" #include "mdss_mdp.h" struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = { @@ -71,6 +72,27 @@ 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) + +struct pp_sts_type { + u32 pa_sts; +}; + +#define PP_FLAGS_DIRTY_PA 0x1 + +#define PP_STS_ENABLE 0x1 + +struct mdss_pp_res_type { + /* logical info */ + u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM]; + struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM]; + /* physical info */ + struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP]; +}; + +static DEFINE_MUTEX(mdss_pp_mutex); +static struct mdss_pp_res_type *mdss_pp_res; + static int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx, struct mdp_csc_cfg *data) { @@ -160,16 +182,147 @@ int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type) return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data); } -int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer) +static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, + struct mdss_mdp_mixer *mixer) { - int dspp_num; + u32 flags, base, offset, dspp_num, opmode = 0; + struct mdp_pa_cfg_data *pa_config; + struct pp_sts_type *pp_sts; + + dspp_num = mixer->num; + /* no corresponding dspp */ + if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) || + (dspp_num >= MDSS_MDP_MAX_DSPP)) + return 0; + + if (disp_num < MDSS_BLOCK_DISP_NUM) + flags = mdss_pp_res->pp_disp_flags[disp_num]; + else + flags = 0; - if (!ctl || !mixer) + /* nothing to update */ + if (!flags) + return 0; + pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num]; + base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num); + if (flags & PP_FLAGS_DIRTY_PA) { + pa_config = &mdss_pp_res->pa_disp_cfg[disp_num]; + if (pa_config->flags & MDP_PP_OPS_WRITE) { + offset = base + MDSS_MDP_REG_DSPP_PA_BASE; + MDSS_MDP_REG_WRITE(offset, pa_config->hue_adj); + offset += 4; + MDSS_MDP_REG_WRITE(offset, pa_config->sat_adj); + offset += 4; + MDSS_MDP_REG_WRITE(offset, pa_config->val_adj); + offset += 4; + MDSS_MDP_REG_WRITE(offset, pa_config->cont_adj); + } + if (pa_config->flags & MDP_PP_OPS_DISABLE) + pp_sts->pa_sts &= ~PP_STS_ENABLE; + else if (pa_config->flags & MDP_PP_OPS_ENABLE) + pp_sts->pa_sts |= PP_STS_ENABLE; + } + if (pp_sts->pa_sts & PP_STS_ENABLE) + opmode |= (1 << 20); /* PA_EN */ + MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode); + ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */ + return 0; + +} +int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl) +{ + u32 disp_num; + if ((!ctl->mfd) || (!mdss_pp_res)) return -EINVAL; - dspp_num = mixer->num; + /* treat fb_num the same as block logical id*/ + disp_num = ctl->mfd->index; - ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */ + mutex_lock(&mdss_pp_mutex); + if (ctl->mixer_left) + pp_dspp_setup(disp_num, ctl, ctl->mixer_left); + if (ctl->mixer_right) + pp_dspp_setup(disp_num, ctl, ctl->mixer_right); + /* clear dirty flag */ + if (disp_num < MDSS_BLOCK_DISP_NUM) + mdss_pp_res->pp_disp_flags[disp_num] = 0; + mutex_unlock(&mdss_pp_mutex); return 0; } + +int mdss_mdp_pp_init(struct device *dev) +{ + int ret = 0; + mutex_lock(&mdss_pp_mutex); + if (!mdss_pp_res) { + mdss_pp_res = devm_kzalloc(dev, sizeof(*mdss_pp_res), + GFP_KERNEL); + if (mdss_pp_res == NULL) { + pr_err("%s mdss_pp_res allocation failed!", __func__); + ret = -ENOMEM; + } + } + mutex_unlock(&mdss_pp_mutex); + return ret; +} +void mdss_mdp_pp_term(struct device *dev) +{ + if (!mdss_pp_res) { + mutex_lock(&mdss_pp_mutex); + devm_kfree(dev, mdss_pp_res); + mdss_pp_res = NULL; + mutex_unlock(&mdss_pp_mutex); + } +} + +int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback) +{ + int i, ret = 0; + u32 pa_offset, disp_num, mixer_cnt; + u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER]; + + if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) || + (config->block >= MDP_BLOCK_MAX)) + return -EINVAL; + + mutex_lock(&mdss_pp_mutex); + disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; + + if (config->flags & MDP_PP_OPS_READ) { + mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id); + if (!mixer_cnt) { + ret = -EPERM; + goto pa_config_exit; + } + /* only read the first mixer */ + for (i = 0; i < mixer_cnt; i++) { + if (mixer_id[i] < MDSS_MDP_MAX_DSPP) + break; + } + if (i >= mixer_cnt) { + ret = -EPERM; + goto pa_config_exit; + } + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); + pa_offset = MDSS_MDP_REG_DSPP_OFFSET(mixer_id[i]) + + MDSS_MDP_REG_DSPP_PA_BASE; + + config->hue_adj = MDSS_MDP_REG_READ(pa_offset); + pa_offset += 4; + config->sat_adj = MDSS_MDP_REG_READ(pa_offset); + pa_offset += 4; + config->val_adj = MDSS_MDP_REG_READ(pa_offset); + pa_offset += 4; + config->cont_adj = MDSS_MDP_REG_READ(pa_offset); + *copyback = 1; + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + } else { + mdss_pp_res->pa_disp_cfg[disp_num] = *config; + mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA; + } + +pa_config_exit: + mutex_unlock(&mdss_pp_mutex); + return ret; +} |
