Skip to content

Commit

Permalink
mdss: Implement PCC combining for LiveDisplay
Browse files Browse the repository at this point in the history
* If we send flicker free data via ioctl, we want to make sure
   it's preserved when applying RGB offsets via LiveDisplay.
 * Add support for combining the values, using the flicker
   free PCC value as a scaling factor.

Signed-off-by: shxyke <shxyke@gmail.com>
  • Loading branch information
aa889788 committed Apr 20, 2020
1 parent d1a49a7 commit ea0d2b0
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 12 deletions.
134 changes: 130 additions & 4 deletions drivers/video/fbdev/msm/flicker_free.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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, &copyback);
return mdss_mdp_kernel_pcc_config(get_mfd_copy(), &pcc_config, &copyback);
}

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;
}
Expand Down Expand Up @@ -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));
Expand Down
13 changes: 11 additions & 2 deletions drivers/video/fbdev/msm/flicker_free.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@

#ifndef _FLICKER_FREE_H
#define _FLICKER_FREE_H
#include <uapi/linux/msm_mdp.h>

#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
Expand Down Expand Up @@ -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 */
2 changes: 2 additions & 0 deletions drivers/video/fbdev/msm/mdss_mdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
57 changes: 57 additions & 0 deletions drivers/video/fbdev/msm/mdss_mdp_pp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions drivers/video/fbdev/msm/mdss_mdp_pp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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
Expand Down
23 changes: 17 additions & 6 deletions drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit ea0d2b0

Please sign in to comment.