/*
|
* Allwinner SoCs display driver.
|
*
|
* Copyright (C) 2016 Allwinner.
|
*
|
* This file is licensed under the terms of the GNU General Public
|
* License version 2. This program is licensed "as is" without any
|
* warranty of any kind, whether express or implied.
|
*/
|
|
/******************************************************************************
|
* All Winner Tech, All Right Reserved. 2014-2015 Copyright (c)
|
*
|
* File name : de_enhance.c
|
*
|
* Description : display engine 2.0 enhance basic function definition
|
*
|
* History : 2014/04/29 vito cheng v0.1 Initial version
|
*
|
*****************************************************************************/
|
#include "de_rtmx.h"
|
#include "de_enhance.h"
|
#include "de_feat.h"
|
#include "de_vep_table.h"
|
|
#define ONE_SCREEN_ONE_PARA
|
/*
|
* only ONE parameters for one screen,
|
* and all VEPs in this screen use SAME parameters
|
*/
|
/* DEBUG */
|
#define ASE_EXIST
|
#define LTI_EXIST
|
#define FCC_EXIST
|
|
static int device_num;
|
static int vep_num[DE_NUM];
|
static unsigned int frame_cnt[DE_NUM] = { 0 };
|
|
static unsigned int g_demo_enable[DE_NUM] = { 0 };
|
static struct disp_enhance_config g_config[DE_NUM];
|
unsigned int g_format[DE_NUM] = { 0xff };
|
unsigned int g_size_bypass[DE_NUM] = { 0 };
|
/* size too small to enable vep */
|
static struct disp_rect g_size[DE_NUM];
|
static bool g_size_change[DE_NUM];
|
|
/* global histogram, use for bws and ce */
|
unsigned int *g_hist[DE_NUM][CHN_NUM];
|
unsigned int *g_hist_p[DE_NUM][CHN_NUM];
|
unsigned int g_sum[DE_NUM][CHN_NUM];
|
|
static unsigned int
|
enhance_mode_to_para[ENHANCE_MODE_NUM][MODE_NUM][FORMAT_NUM][PARA_NUM] = {
|
/* SHARP AUTO_CONTRAST AUTO_COLOR FC_R FC_G FC_B */
|
{
|
/* lcd normal */
|
{
|
/* rgb */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
/* yuv */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
},
|
/* hdmi normal */
|
{
|
/* rgb */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
/* yuv disable all */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
},
|
},
|
/* lcd vivid */
|
{
|
{
|
/* rgb */
|
{0x22, 0x10001, 0x21, 1, 1, 1},
|
/* yuv */
|
{0x11, 0x10010, 0x21, 1, 2, 1},
|
},
|
/* hdmi vivid */
|
{
|
/* rgb */
|
{0x00, 0x00000, 0x21, 1, 1, 1},
|
/* yuv disable all */
|
{0x20, 0x01020, 0x21, 1, 1, 1},
|
},
|
},
|
{
|
/* lcd soft */
|
{
|
/* rgb */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
/* yuv */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
},
|
/* hdmi soft */
|
{
|
/* rgb */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
/* yuv disable all */
|
{0x00, 0x00000, 0x00, 0, 0, 0},
|
}
|
},
|
};
|
|
int de_enhance_info2data(struct disp_enhance_config *config,
|
struct vep_config_data *data, unsigned int bypass)
|
{
|
struct de_rect tmp_win;
|
struct disp_enhance_config tmp_config;
|
|
memcpy(&tmp_config.info, config, sizeof(struct disp_enhance_config));
|
memset(data, 0, sizeof(struct vep_config_data));
|
|
/* FIXME : should be deleted */
|
tmp_win.x = config->info.window.x;
|
tmp_win.y = config->info.window.y;
|
tmp_win.w = config->info.window.width;
|
tmp_win.h = config->info.window.height;
|
/* FIXME end: should be deleted */
|
|
tmp_config.info.sharp = (tmp_config.info.enable == 0
|
|| bypass == 1) ? 0 : tmp_config.info.sharp;
|
tmp_config.info.auto_color = (tmp_config.info.enable == 0
|
|| bypass ==
|
1) ? 0 : tmp_config.info.auto_color;
|
tmp_config.info.auto_contrast = (tmp_config.info.enable == 0
|
|| bypass ==
|
1) ? 0 : tmp_config.info.auto_contrast;
|
tmp_config.info.fancycolor_red = (tmp_config.info.enable == 0
|
|| bypass ==
|
1) ? 0 : tmp_config.info.
|
fancycolor_red;
|
tmp_config.info.fancycolor_green = (tmp_config.info.enable == 0
|
|| bypass ==
|
1) ? 0 : tmp_config.info.
|
fancycolor_green;
|
tmp_config.info.fancycolor_blue = (tmp_config.info.enable == 0
|
|| bypass ==
|
1) ? 0 : tmp_config.info.
|
fancycolor_blue;
|
|
/* FIXME : tmp_win should be deleted */
|
/* fce */
|
de_fce_info2para(tmp_config.info.sharp, tmp_config.info.auto_contrast,
|
tmp_config.info.auto_color, tmp_win, &data->fce_para);
|
|
/* FIXME */
|
/* peak */
|
de_peak_info2para(tmp_config.info.sharp, tmp_win,
|
&data->peak_para);
|
#ifdef LTI_EXIST
|
/* lti */
|
de_lti_info2para(tmp_config.info.sharp, tmp_win,
|
&data->lti_para);
|
#endif
|
#ifdef ASE_EXIST
|
/* ase */
|
de_ase_info2para(tmp_config.info.auto_color, tmp_win, &data->ase_para);
|
#endif
|
#ifdef FCC_EXIST
|
/* fcc */
|
de_fcc_info2para(tmp_config.info.fancycolor_red,
|
tmp_config.info.fancycolor_green,
|
tmp_config.info.fancycolor_blue, 0, 0, 0, tmp_win,
|
&data->fcc_para);
|
#endif
|
|
return 0;
|
}
|
|
int de_enhance_set_format(unsigned int screen_id, unsigned int format)
|
{
|
int format_change = 0;
|
|
if (g_format[screen_id] != format) {
|
g_format[screen_id] = format;
|
format_change = 1;
|
g_config[screen_id].flags |= ENH_FORMAT_DIRTY;
|
}
|
|
if (format_change == 1 || g_size_change[screen_id])
|
de_enhance_apply(screen_id, &g_config[screen_id]);
|
|
return 0;
|
}
|
|
int de_enhance_apply(unsigned int screen_id,
|
struct disp_enhance_config *config)
|
{
|
int ch_id, chno;
|
struct vep_config_data *data;
|
int auto_contrast_dirty;
|
|
data = kmalloc(sizeof(struct vep_config_data), GFP_KERNEL | __GFP_ZERO);
|
if (!data) {
|
__wrn("kmalloc fail!\n");
|
goto err;
|
}
|
chno = vep_num[screen_id];
|
|
__inf("disp %d, en=%d, sharp=%d\n", screen_id, config[0].info.enable,
|
config[0].info.sharp);
|
memcpy(&g_config[screen_id], config,
|
sizeof(struct disp_enhance_config));
|
de_enhance_set_mode(g_format[screen_id], config);
|
for (ch_id = 0; ch_id < chno; ch_id++) {
|
auto_contrast_dirty = (config[0].flags & (ENH_ENABLE_DIRTY
|
| ENH_SIZE_DIRTY
|
| ENH_FORMAT_DIRTY
|
| ENH_MODE_DIRTY)) ?
|
1 : 0;
|
|
/* disp_enhance_info -> vep_config_data */
|
de_enhance_info2data(&config[0], data,
|
g_size_bypass[screen_id]);
|
/* FIXME: Update according to dirty flag */
|
/* fce */
|
de_hist_apply(screen_id, ch_id, data->fce_para.hist_en,
|
auto_contrast_dirty);
|
de_ce_apply(screen_id, ch_id, data->fce_para.ce_en,
|
data->fce_para.b_automode,
|
data->fce_para.up_precent_thr,
|
data->fce_para.down_precent_thr,
|
data->fce_para.update_diff_thr,
|
data->fce_para.slope_black_lmt,
|
data->fce_para.slope_white_lmt,
|
auto_contrast_dirty);
|
de_fce_enable(screen_id, ch_id, data->fce_para.fce_en);
|
de_fce_set_para(screen_id, ch_id, data->fce_para);
|
|
/* peak */
|
de_peak_enable(screen_id, ch_id, data->peak_para.peak_en);
|
de_peak_set_para(screen_id, ch_id, data->peak_para.gain,
|
data->peak_para.hp_ratio,
|
data->peak_para.bp0_ratio);
|
|
/* lti */
|
de_lti_enable(screen_id, ch_id, data->lti_para.lti_en);
|
de_lti_set_para(screen_id, ch_id, data->lti_para.lti_en);
|
|
/* ase */
|
de_ase_enable(screen_id, ch_id, data->ase_para.ase_en);
|
de_ase_set_para(screen_id, ch_id, data->ase_para.gain);
|
|
/* fcc */
|
de_fcc_enable(screen_id, ch_id, data->fcc_para.fcc_en);
|
de_fcc_set_para(screen_id, ch_id, data->fcc_para.sgain);
|
|
}
|
de_enhance_demo_enable(screen_id, config[0].info.demo_enable);
|
g_config[screen_id].flags = 0;
|
|
kfree(data);
|
err:
|
return 0;
|
}
|
|
int de_enhance_set_size(unsigned int screen_id, struct disp_rect *size)
|
{
|
int ch_id, chno;
|
struct de_rect tmp_win;
|
unsigned int demo_enable;
|
|
chno = vep_num[screen_id];
|
demo_enable = g_demo_enable[screen_id] ? 1 : 0;
|
|
for (ch_id = 0; ch_id < chno; ch_id++) {
|
tmp_win.x = 0;
|
tmp_win.y = 0;
|
if (demo_enable) {
|
if (size[ch_id].width > size[ch_id].height) {
|
tmp_win.w = size[ch_id].width >> 1;
|
tmp_win.h = size[ch_id].height;
|
} else {
|
tmp_win.w = size[ch_id].width;
|
tmp_win.h = size[ch_id].height >> 1;
|
}
|
} else {
|
tmp_win.w = size[ch_id].width;
|
tmp_win.h = size[ch_id].height;
|
}
|
|
/* fce */
|
de_fce_set_size(screen_id, ch_id, size[ch_id].width,
|
size[ch_id].height);
|
de_fce_set_window(screen_id, ch_id, demo_enable, tmp_win);
|
g_ce_status[screen_id][ch_id]->width = size[ch_id].width;
|
g_ce_status[screen_id][ch_id]->height = size[ch_id].height;
|
|
/* peak */
|
de_peak_set_size(screen_id, ch_id, size[ch_id].width,
|
size[ch_id].height);
|
de_peak_set_window(screen_id, ch_id, demo_enable, tmp_win);
|
|
/* lti */
|
de_lti_set_size(screen_id, ch_id, size[ch_id].width,
|
size[ch_id].height);
|
de_lti_set_window(screen_id, ch_id, demo_enable, tmp_win);
|
|
/* ase */
|
de_ase_set_size(screen_id, ch_id, size[ch_id].width,
|
size[ch_id].height);
|
de_ase_set_window(screen_id, ch_id, demo_enable, tmp_win);
|
|
/* fcc */
|
de_fcc_set_size(screen_id, ch_id, size[ch_id].width,
|
size[ch_id].height);
|
de_fcc_set_window(screen_id, ch_id, demo_enable, tmp_win);
|
}
|
|
if ((size->width != g_size[screen_id].width)
|
|| (size->height != g_size[screen_id].height)) {
|
g_size_change[screen_id] = true;
|
g_config[screen_id].flags |= ENH_SIZE_DIRTY;
|
} else
|
g_size_change[screen_id] = false;
|
memcpy(&g_size[screen_id], size, sizeof(struct disp_rect));
|
|
if (size[0].width < ENAHNCE_MIN_WIDTH
|
|| size[0].height < ENAHNCE_MIN_HEIGHT) {
|
g_size_bypass[screen_id] = 1;
|
} else {
|
g_size_bypass[screen_id] = 0;
|
}
|
|
return 0;
|
}
|
|
int de_enhance_demo_enable(unsigned int screen_id, unsigned int enable)
|
{
|
if (enable)
|
g_demo_enable[screen_id] = 1;
|
else
|
g_demo_enable[screen_id] = 0;
|
return 0;
|
}
|
|
int de_enhance_sync(unsigned int screen_id)
|
{
|
return 0;
|
}
|
|
int de_enhance_tasklet(unsigned int screen_id)
|
{
|
int ch_id, chno;
|
|
chno = vep_num[screen_id];
|
|
for (ch_id = 0; ch_id < chno; ch_id++) {
|
/* hist */
|
de_hist_tasklet(screen_id, ch_id, frame_cnt[screen_id]);
|
|
/* ce */
|
de_ce_tasklet(screen_id, ch_id, frame_cnt[screen_id]);
|
frame_cnt[screen_id]++;
|
}
|
return 0;
|
}
|
|
int de_enhance_update_regs(unsigned int screen_id)
|
{
|
int chno, ch_id;
|
|
chno = vep_num[screen_id];
|
for (ch_id = 0; ch_id < chno; ch_id++) {
|
de_fce_update_regs(screen_id, ch_id);
|
#ifdef LTI_EXIST
|
de_lti_update_regs(screen_id, ch_id);
|
#endif
|
de_peak_update_regs(screen_id, ch_id);
|
#ifdef ASE_EXIST
|
de_ase_update_regs(screen_id, ch_id);
|
#endif
|
#ifdef FCC_EXIST
|
de_fcc_update_regs(screen_id, ch_id);
|
#endif
|
}
|
return 0;
|
}
|
|
int de_enhance_init(struct disp_bsp_init_para *para)
|
{
|
int screen_id, ch_id;
|
|
device_num = de_feat_get_num_screens();
|
|
for (screen_id = 0; screen_id < device_num; screen_id++)
|
vep_num[screen_id] = de_feat_is_support_vep(screen_id);
|
|
for (screen_id = 0; screen_id < device_num; screen_id++)
|
for (ch_id = 0; ch_id < vep_num[screen_id]; ch_id++) {
|
#if defined(CONFIG_INDEPENDENT_DE)
|
de_fce_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE + screen_id]);
|
#ifdef LTI_EXIST
|
de_lti_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE + screen_id]);
|
#endif
|
de_peak_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE + screen_id]);
|
#ifdef ASE_EXIST
|
de_ase_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE + screen_id]);
|
#endif
|
#ifdef FCC_EXIST
|
de_fcc_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE + screen_id]);
|
#endif
|
#else/*for CONFIG_INDEPENDENT_DE*/
|
de_fce_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE]);
|
#ifdef LTI_EXIST
|
de_lti_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE]);
|
#endif
|
de_peak_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE]);
|
#ifdef ASE_EXIST
|
de_ase_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE]);
|
#endif
|
#ifdef FCC_EXIST
|
de_fcc_init(screen_id, ch_id,
|
para->reg_base[DISP_MOD_DE]);
|
#endif
|
#endif
|
}
|
|
/* initial */
|
for (screen_id = 0; screen_id < device_num; screen_id++)
|
frame_cnt[screen_id] = 0;
|
|
return 0;
|
}
|
|
int de_enhance_exit(void)
|
{
|
int screen_id, ch_id;
|
|
device_num = de_feat_get_num_screens();
|
|
for (screen_id = 0; screen_id < device_num; screen_id++)
|
vep_num[screen_id] = de_feat_is_support_vep(screen_id);
|
|
for (screen_id = 0; screen_id < device_num; screen_id++)
|
for (ch_id = 0; ch_id < vep_num[screen_id]; ch_id++) {
|
de_fce_exit(screen_id, ch_id);
|
#ifdef LTI_EXIST
|
de_lti_exit(screen_id, ch_id);
|
#endif
|
de_peak_exit(screen_id, ch_id);
|
#ifdef ASE_EXIST
|
de_ase_exit(screen_id, ch_id);
|
#endif
|
#ifdef FCC_EXIST
|
de_fcc_exit(screen_id, ch_id);
|
#endif
|
}
|
|
return 0;
|
}
|
|
int de_enhance_set_mode(unsigned int format, struct disp_enhance_config *config)
|
{
|
unsigned int mode, enhance_mode;
|
|
mode = config->info.mode & 0xffff;
|
enhance_mode = (config->info.mode & 0xffff0000) >> 16;
|
|
if ((mode >= MODE_NUM) || (format >= 2)
|
|| (enhance_mode >= ENHANCE_MODE_NUM)) {
|
__wrn("para excess! mode = %d, enhance_mode = %d, format=%d\n",
|
mode, enhance_mode, format);
|
return 1;
|
}
|
|
config->info.sharp =
|
enhance_mode_to_para[enhance_mode][mode][format][0];
|
config->info.auto_contrast =
|
enhance_mode_to_para[enhance_mode][mode][format][1];
|
config->info.auto_color =
|
enhance_mode_to_para[enhance_mode][mode][format][2];
|
config->info.fancycolor_red =
|
enhance_mode_to_para[enhance_mode][mode][format][3];
|
config->info.fancycolor_green =
|
enhance_mode_to_para[enhance_mode][mode][format][4];
|
config->info.fancycolor_blue =
|
enhance_mode_to_para[enhance_mode][mode][format][5];
|
|
return 0;
|
}
|