diff --git a/drivers/video/fbdev/msm/flicker_free.c b/drivers/video/fbdev/msm/flicker_free.c index 03570275c863..0c827fb5725b 100644 --- a/drivers/video/fbdev/msm/flicker_free.c +++ b/drivers/video/fbdev/msm/flicker_free.c @@ -80,7 +80,7 @@ static int flicker_free_push_dither(int depth) static int flicker_free_push_pcc(int temp) { - pcc_config.ops = mdss_backlight_enable ? + pcc_config.ops = pcc_enabled ? MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE : MDP_PP_OPS_WRITE | MDP_PP_OPS_DISABLE; pcc_config.r.r = temp; @@ -91,14 +91,14 @@ static int flicker_free_push_pcc(int temp) payload->b.b = pcc_config.b.b; pcc_config.cfg_payload = payload; - return mdss_mdp_pcc_config(get_mfd_copy(), &pcc_config, ©back); + return mdss_mdp_kernel_pcc_config(get_mfd_copy(), &pcc_config, ©back); } static int set_brightness(int backlight) { - int temp = 0; + uint32_t temp = 0; backlight = clamp_t(int, ((backlight-1)*(BACKLIGHT_INDEX-1)/(elvss_off_threshold-1)+1), 1, BACKLIGHT_INDEX); - temp = clamp_t(int, 0x80*bkl_to_pcc[backlight - 1], MIN_SCALE, MAX_SCALE); + temp = clamp_t(int, 0x80*bkl_to_pcc[backlight - 1], FF_MIN_SCALE, FF_MAX_SCALE); for (depth = 8;depth >= 1;depth--){ if(temp >= pcc_depth[depth]) break; } @@ -172,6 +172,132 @@ bool if_flicker_free_enabled(void) return mdss_backlight_enable; } +static u32 pcc_rescale(u32 raw, u32 user) +{ + u32 val = 0; + + if (raw == 0 || raw > 32768) + raw = 32768; + if (user == 0 || user > 32768) + user = 32768; + val = (raw * user) / 32768; + return val < 2560 ? 2560 : val; +} + +void pcc_v1_7_combine(struct mdp_pcc_data_v1_7 **raw, + struct mdp_pcc_data_v1_7 **user, + struct mdp_pcc_data_v1_7 **real) +{ + struct mdp_pcc_data_v1_7 *real_cpy; + real_cpy = kzalloc(sizeof(struct mdp_pcc_data_v1_7), GFP_USER); + if (!(*real)) { + *real = kzalloc(sizeof(struct mdp_pcc_data_v1_7), GFP_USER); + if (!(*real)) { + pr_err("%s: alloc failed!", __func__); + return; + } + } + if((*raw)&&(*user)){ + real_cpy->r.c = (*user)->r.c? pcc_rescale((*raw)->r.r, (*user)->r.c)*3/4: 0; + real_cpy->r.r = (*user)->r.g? pcc_rescale((*raw)->r.r, (*user)->r.r)*3/4: pcc_rescale((*raw)->r.r, (*user)->r.r); + real_cpy->r.g = (*user)->r.g? pcc_rescale((*raw)->r.r, (*user)->r.g)*3/4: 0; + real_cpy->r.b = (*user)->r.b? pcc_rescale((*raw)->r.r, (*user)->r.b)*3/4: 0; + real_cpy->r.rg = (*user)->r.rg? pcc_rescale((*raw)->r.r, (*user)->r.rg)*3/4: 0; + real_cpy->r.gb = (*user)->r.gb? pcc_rescale((*raw)->r.r, (*user)->r.gb)*3/4: 0; + real_cpy->r.rb = (*user)->r.rb? pcc_rescale((*raw)->r.r, (*user)->r.rb)*3/4: 0; + real_cpy->r.rgb = (*user)->r.rgb? pcc_rescale((*raw)->r.r, (*user)->r.rgb)*3/4: 0; + real_cpy->g.c = (*user)->g.c? pcc_rescale((*raw)->r.r, (*user)->g.c)*3/4: 0; + real_cpy->g.g = (*user)->g.r? pcc_rescale((*raw)->r.r, (*user)->g.g)*3/4: pcc_rescale((*raw)->r.r, (*user)->g.g); + real_cpy->g.r = (*user)->g.r? pcc_rescale((*raw)->r.r, (*user)->g.r)*3/4: 0; + real_cpy->g.b = (*user)->g.b? pcc_rescale((*raw)->r.r, (*user)->g.b)*3/4: 0; + real_cpy->g.rg = (*user)->g.rg? pcc_rescale((*raw)->r.r, (*user)->g.rg)*3/4: 0; + real_cpy->g.gb = (*user)->g.gb? pcc_rescale((*raw)->r.r, (*user)->g.gb)*3/4: 0; + real_cpy->g.rb = (*user)->g.rb? pcc_rescale((*raw)->r.r, (*user)->g.rb)*3/4: 0; + real_cpy->g.rgb = (*user)->g.rgb? pcc_rescale((*raw)->r.r, (*user)->g.rgb)*3/4: 0; + real_cpy->b.c = (*user)->b.c? pcc_rescale((*raw)->r.r, (*user)->b.c)*3/4: 0; + real_cpy->b.b = (*user)->b.r? pcc_rescale((*raw)->r.r, (*user)->b.b)*3/4: pcc_rescale((*raw)->r.r, (*user)->b.b); + real_cpy->b.r = (*user)->b.r? pcc_rescale((*raw)->r.r, (*user)->b.r)*3/4: 0; + real_cpy->b.g = (*user)->b.g? pcc_rescale((*raw)->r.r, (*user)->b.g)*3/4: 0; + real_cpy->b.rg = (*user)->b.rg? pcc_rescale((*raw)->r.r, (*user)->b.rg)*3/4: 0; + real_cpy->b.gb = (*user)->b.gb? pcc_rescale((*raw)->r.r, (*user)->b.gb)*3/4: 0; + real_cpy->b.rb = (*user)->b.rb? pcc_rescale((*raw)->r.r, (*user)->b.rb)*3/4: 0; + real_cpy->b.rgb = (*user)->b.rgb? pcc_rescale((*raw)->r.r, (*user)->b.rgb)*3/4: 0; + }else{ + if((*user)){ + memcpy(real_cpy, (*user), sizeof(struct mdp_pcc_data_v1_7)); + }else{ + if((*raw)){ + real_cpy->r.r = (*raw)->r.r; + real_cpy->g.g = (*raw)->g.g; + real_cpy->b.b = (*raw)->b.b; + }else{ + real_cpy->r.r = 32768; + real_cpy->g.g = 32768; + real_cpy->b.b = 32768; + } + } + } + memcpy(*real, real_cpy, sizeof(struct mdp_pcc_data_v1_7)); + kfree(real_cpy); +} + +void pcc_combine(struct mdp_pcc_cfg_data *raw, + struct mdp_pcc_cfg_data *user, + struct mdp_pcc_cfg_data *real) +{ + uint32_t r_ops, u_ops, r_en, u_en; + struct mdp_pcc_data_v1_7 *v17_ff_data, *v17_user_data, + *v17_real_data,*payload; + + if (!real) { + real = kzalloc(sizeof(struct mdp_pcc_cfg_data), GFP_KERNEL); + payload = kzalloc(sizeof(struct mdp_pcc_data_v1_7), GFP_USER); + payload->r.r = payload->g.g = payload->b.b = 32768; + real->cfg_payload = payload; + if (!real) { + pr_err("%s: alloc failed!", __func__); + return; + } + } + + real->version = mdp_pcc_v1_7; + real->block = MDP_LOGICAL_BLOCK_DISP_0; + + r_ops = raw->cfg_payload ? raw->ops : MDP_PP_OPS_DISABLE; + u_ops = user->cfg_payload ? user->ops : MDP_PP_OPS_DISABLE; + r_en = raw && !(raw->ops & MDP_PP_OPS_DISABLE); + u_en = user && !(user->ops & MDP_PP_OPS_DISABLE); + + // user configuration may change often, but the raw configuration + // will correspond to calibration data which should only change if + // there is a mode switch. we only care about the base + // coefficients from the user config. + + if (!r_en || (raw->r.r == 0 && raw->g.g == 0 && raw->b.b == 0)){ + raw->r.r = raw->g.g = raw->b.b = 32768; + } + if (!u_en || (user->r.r == 0 && user->g.g == 0 && user->b.b ==0)){ + user->r.r = user->g.g = user->b.b = 32768; + } + + + real->r.r = pcc_rescale(raw->r.r, user->r.r); + real->g.g = pcc_rescale(raw->g.g, user->g.g); + real->b.b = pcc_rescale(raw->b.b, user->b.b); + v17_ff_data = raw->cfg_payload; + v17_user_data = user->cfg_payload; + v17_real_data = real->cfg_payload; + pcc_v1_7_combine(&v17_ff_data, &v17_user_data, &v17_real_data); + if (r_en && u_en) + real->ops = r_ops | u_ops; + else if (r_en) + real->ops = r_ops; + else if (u_en) + real->ops = u_ops; + else + real->ops = MDP_PP_OPS_DISABLE; +} + static int __init flicker_free_init(void) { memset(&pcc_config, 0, sizeof(struct mdp_pcc_cfg_data)); diff --git a/drivers/video/fbdev/msm/flicker_free.h b/drivers/video/fbdev/msm/flicker_free.h index 6cb7466d3257..3a3934f2ee05 100644 --- a/drivers/video/fbdev/msm/flicker_free.h +++ b/drivers/video/fbdev/msm/flicker_free.h @@ -21,10 +21,11 @@ #ifndef _FLICKER_FREE_H #define _FLICKER_FREE_H +#include -#define MAX_SCALE 32768 /* Maximum value of RGB possible */ +#define FF_MAX_SCALE 32768 /* Maximum value of RGB possible */ -#define MIN_SCALE 5120 /* Minimum value of RGB recommended */ +#define FF_MIN_SCALE 5120 /* Minimum value of RGB recommended */ #define RET_WORKGROUND #define RET_WORKGROUND_DELAY 200 @@ -56,4 +57,12 @@ int get_elvss_off_threshold(void); /* get the current flicker free status (enabled or disabled) */ bool if_flicker_free_enabled(void); +void pcc_v1_7_combine(struct mdp_pcc_data_v1_7 **raw, + struct mdp_pcc_data_v1_7 **user, + struct mdp_pcc_data_v1_7 **real); + +void pcc_combine(struct mdp_pcc_cfg_data *raw, + struct mdp_pcc_cfg_data *user, + struct mdp_pcc_cfg_data *real); + #endif /* _FLICKER_FREE_H */ diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 9c93c500d127..176e22ce7c26 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1853,6 +1853,8 @@ int mdss_mdp_pa_config(struct msm_fb_data_type *mfd, struct mdp_pa_cfg_data *config, u32 *copyback); int mdss_mdp_pa_v2_config(struct msm_fb_data_type *mfd, struct mdp_pa_v2_cfg_data *config, u32 *copyback); +int mdss_mdp_kernel_pcc_config(struct msm_fb_data_type *mfd, + struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback); int mdss_mdp_pcc_config(struct msm_fb_data_type *mfd, struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback); int mdss_mdp_igc_lut_config(struct msm_fb_data_type *mfd, diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index ef86483dfca0..41374707d3c4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -3879,6 +3879,63 @@ static void pp_update_pcc_regs(char __iomem *addr, writel_relaxed(cfg_ptr->b.rgb_1, addr + 8); } +int mdss_mdp_kernel_pcc_config(struct msm_fb_data_type *mfd, + struct mdp_pcc_cfg_data *config, + u32 *copyback) +{ + int ret = 0; + u32 disp_num; + struct mdss_pp_res_type_v1_7 *res_cache; + struct mdp_pcc_data_v1_7 *v17_kernel_data, v17_usr_config, + *v17_user_data, *v17_real_data; + + 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; + } + mutex_lock(&mdss_pp_mutex); + disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; + + if (!config || !mdss_pp_res) { + pr_err("invalid param config %pK pp_res %pK\n", + config, mdss_pp_res); + return -EINVAL; + } + + res_cache = mdss_pp_res->pp_data_v1_7; + mdss_pp_res->kernel_pcc_disp_cfg[disp_num] = *config; + v17_kernel_data = &res_cache->kernel_pcc_v17_data[disp_num]; + v17_user_data = &res_cache->user_pcc_v17_data[disp_num]; + v17_real_data = &res_cache->pcc_v17_data[disp_num]; + mdss_pp_res->kernel_pcc_disp_cfg[disp_num].cfg_payload = + (void *) v17_kernel_data; + mdss_pp_res->user_pcc_disp_cfg[disp_num].cfg_payload = + (void *) v17_user_data; + mdss_pp_res->pcc_disp_cfg[disp_num].cfg_payload = + (void *) v17_real_data; + memcpy(&v17_usr_config, config->cfg_payload, sizeof(v17_usr_config)); + ret = 0; + if ((config->ops & MDP_PP_OPS_DISABLE)&& + !(config->ops & MDP_PP_OPS_WRITE)) { + pr_debug("disable pcc\n"); + pr_debug("op for pcc %d\n", config->ops); + ret = 0; + goto kernel_pcc_config_exit; + } + memcpy(v17_kernel_data, &v17_usr_config, sizeof(v17_usr_config)); + pcc_combine(&mdss_pp_res->kernel_pcc_disp_cfg[disp_num], + &mdss_pp_res->user_pcc_disp_cfg[disp_num], + &mdss_pp_res->pcc_disp_cfg[disp_num]); + pcc_v1_7_combine(&v17_kernel_data, &v17_user_data, &v17_real_data); + mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PCC; +kernel_pcc_config_exit: + mutex_unlock(&mdss_pp_mutex); + return ret; +} + int mdss_mdp_pcc_config(struct msm_fb_data_type *mfd, struct mdp_pcc_cfg_data *config, u32 *copyback) diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h index 136e2d79787c..7ce5cd84b710 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.h +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h @@ -136,6 +136,8 @@ struct mdss_pp_res_type_v1_7 { struct mdp_hist_lut_data_v1_7 hist_lut_v17_data[MDSS_BLOCK_DISP_NUM]; struct mdp_dither_data_v1_7 dither_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 kernel_pcc_v17_data[MDSS_BLOCK_DISP_NUM]; + struct mdp_pcc_data_v1_7 user_pcc_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]; @@ -187,6 +189,8 @@ struct mdss_pp_res_type { struct mdp_dither_cfg_data pa_dither_cfg[MDSS_BLOCK_DISP_NUM]; /* physical info */ struct pp_hist_col_info *dspp_hist; + struct mdp_pcc_cfg_data kernel_pcc_disp_cfg[MDSS_BLOCK_DISP_NUM]; + struct mdp_pcc_cfg_data user_pcc_disp_cfg[MDSS_BLOCK_DISP_NUM]; /* * The pp_data_v1_7 will be a pointer to newer MDP revisions of the * pp_res, which will hold the cfg_payloads of each feature in a single 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 965dee364df2..12f660757170 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c @@ -650,7 +650,8 @@ static int pp_pcc_cache_params_v1_7(struct mdp_pcc_cfg_data *config, u32 disp_num; int ret = 0; struct mdss_pp_res_type_v1_7 *res_cache; - struct mdp_pcc_data_v1_7 *v17_cache_data, v17_usr_config; + struct mdp_pcc_data_v1_7 *v17_kernel_data, v17_usr_config, + *v17_user_data, *v17_real_data; if (!config || !mdss_pp_res) { pr_err("invalid param config %pK pp_res %pK\n", @@ -674,10 +675,16 @@ static int pp_pcc_cache_params_v1_7(struct mdp_pcc_cfg_data *config, return -EINVAL; } else { disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; - mdss_pp_res->pcc_disp_cfg[disp_num] = *config; - v17_cache_data = &res_cache->pcc_v17_data[disp_num]; + mdss_pp_res->user_pcc_disp_cfg[disp_num] = *config; + v17_kernel_data = &res_cache->kernel_pcc_v17_data[disp_num]; + v17_user_data = &res_cache->user_pcc_v17_data[disp_num]; + v17_real_data = &res_cache->pcc_v17_data[disp_num]; + mdss_pp_res->kernel_pcc_disp_cfg[disp_num].cfg_payload = + (void *) v17_kernel_data; + mdss_pp_res->user_pcc_disp_cfg[disp_num].cfg_payload = + (void *) v17_user_data; mdss_pp_res->pcc_disp_cfg[disp_num].cfg_payload = - (void *) v17_cache_data; + (void *) v17_real_data; if (copy_from_user(&v17_usr_config, config->cfg_payload, sizeof(v17_usr_config))) { #if defined(CONFIG_FB_MSM_MDSS_KCAL_CTRL) || defined(CONFIG_FLICKER_FREE) @@ -696,9 +703,13 @@ static int pp_pcc_cache_params_v1_7(struct mdp_pcc_cfg_data *config, } if (!(config->ops & MDP_PP_OPS_WRITE)) { pr_debug("op for pcc %d\n", config->ops); - goto pcc_config_exit; + goto pcc_config_exit; } - memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config)); + memcpy(v17_user_data, &v17_usr_config, sizeof(v17_usr_config)); + pcc_combine(&mdss_pp_res->kernel_pcc_disp_cfg[disp_num], + &mdss_pp_res->user_pcc_disp_cfg[disp_num], + &mdss_pp_res->pcc_disp_cfg[disp_num]); + pcc_v1_7_combine(&v17_kernel_data, &v17_user_data, &v17_real_data); } pcc_config_exit: return ret;