msm: mdss: Add support for IGC in thulium
Inverse gamma correction(IGC) feature is exposed by the MDP hardware block in source and destination pipes. Clients of the post processing driver can program the IGC tables and enable the feature. This change adds support for IGC post processing feature. Change-Id: I177fb06f5eec58fea0a54b537c0009d4c8e01bd7 Signed-off-by: Ping Li <pingli@codeaurora.org>
This commit is contained in:
parent
947a5d6ac5
commit
2026a16aed
6 changed files with 391 additions and 29 deletions
|
@ -737,27 +737,25 @@ static void pp_igc_config(unsigned long flags, char __iomem *addr,
|
|||
u32 pipe_num, u32 pipe_cnt)
|
||||
{
|
||||
u32 tbl_idx;
|
||||
if (flags & PP_FLAGS_DIRTY_IGC) {
|
||||
if (igc_config->ops & MDP_PP_OPS_WRITE)
|
||||
pp_update_igc_lut(igc_config, addr, pipe_num,
|
||||
pipe_cnt);
|
||||
if (igc_config->ops & MDP_PP_OPS_WRITE)
|
||||
pp_update_igc_lut(igc_config, addr, pipe_num,
|
||||
pipe_cnt);
|
||||
|
||||
if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
|
||||
pp_sts->pcc_sts |= PP_STS_ENABLE;
|
||||
tbl_idx = 1;
|
||||
} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
|
||||
pp_sts->pcc_sts |= PP_STS_ENABLE;
|
||||
tbl_idx = 2;
|
||||
} else {
|
||||
tbl_idx = 0;
|
||||
}
|
||||
pp_sts->igc_tbl_idx = tbl_idx;
|
||||
if (igc_config->ops & MDP_PP_OPS_DISABLE)
|
||||
pp_sts->igc_sts &= ~PP_STS_ENABLE;
|
||||
else if (igc_config->ops & MDP_PP_OPS_ENABLE)
|
||||
pp_sts->igc_sts |= PP_STS_ENABLE;
|
||||
pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
|
||||
if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
|
||||
pp_sts->igc_sts |= PP_STS_ENABLE;
|
||||
tbl_idx = 1;
|
||||
} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
|
||||
pp_sts->igc_sts |= PP_STS_ENABLE;
|
||||
tbl_idx = 2;
|
||||
} else {
|
||||
tbl_idx = 0;
|
||||
}
|
||||
pp_sts->igc_tbl_idx = tbl_idx;
|
||||
if (igc_config->ops & MDP_PP_OPS_DISABLE)
|
||||
pp_sts->igc_sts &= ~PP_STS_ENABLE;
|
||||
else if (igc_config->ops & MDP_PP_OPS_ENABLE)
|
||||
pp_sts->igc_sts |= PP_STS_ENABLE;
|
||||
pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
|
||||
}
|
||||
|
||||
static void pp_enhist_config(unsigned long flags, char __iomem *addr,
|
||||
|
@ -1569,7 +1567,7 @@ static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
|
|||
return;
|
||||
|
||||
if (pp_driver_ops.pp_opmode_config) {
|
||||
pp_driver_ops.pp_opmode_config(PP_OPMODE_DSPP,
|
||||
pp_driver_ops.pp_opmode_config(DSPP,
|
||||
pp_sts, opmode, side);
|
||||
return;
|
||||
}
|
||||
|
@ -1709,9 +1707,21 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
|
|||
}
|
||||
}
|
||||
|
||||
pp_igc_config(flags, mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE,
|
||||
pp_sts, &mdss_pp_res->igc_disp_cfg[disp_num],
|
||||
dspp_num, mdata->ndspp);
|
||||
if (flags & PP_FLAGS_DIRTY_IGC) {
|
||||
if (!pp_ops[IGC].pp_set_config) {
|
||||
pp_igc_config(flags,
|
||||
mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE,
|
||||
pp_sts, &mdss_pp_res->igc_disp_cfg[disp_num],
|
||||
dspp_num, mdata->ndspp);
|
||||
} else {
|
||||
addr = mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE;
|
||||
/* Pass dspp num using block */
|
||||
mdss_pp_res->igc_disp_cfg[disp_num].block = dspp_num;
|
||||
pp_ops[IGC].pp_set_config(addr, pp_sts,
|
||||
&mdss_pp_res->igc_disp_cfg[disp_num],
|
||||
DSPP);
|
||||
}
|
||||
}
|
||||
|
||||
pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
|
||||
pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
|
||||
|
@ -2926,9 +2936,16 @@ int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config,
|
|||
&mdss_pp_res->igc_lut_c2[disp_num][0];
|
||||
if (mdata->has_no_lut_read)
|
||||
pp_read_igc_lut_cached(&local_cfg);
|
||||
else
|
||||
pp_read_igc_lut(&local_cfg, igc_addr, dspp_num,
|
||||
mdata->ndspp);
|
||||
else {
|
||||
if (pp_ops[IGC].pp_get_config) {
|
||||
pp_ops[IGC].pp_get_config(igc_addr, config,
|
||||
DSPP, disp_num);
|
||||
goto clock_off;
|
||||
} else {
|
||||
pp_read_igc_lut(&local_cfg, igc_addr,
|
||||
dspp_num, mdata->ndspp);
|
||||
}
|
||||
}
|
||||
if (copy_to_user(config->c0_c1_data, local_cfg.c0_c1_data,
|
||||
config->len * sizeof(u32))) {
|
||||
ret = -EFAULT;
|
||||
|
@ -2942,8 +2959,18 @@ int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config,
|
|||
goto igc_config_exit;
|
||||
}
|
||||
*copyback = 1;
|
||||
clock_off:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
} else {
|
||||
if (pp_ops[IGC].pp_set_config) {
|
||||
ret = pp_igc_lut_cache_params(config,
|
||||
mdss_pp_res, copy_from_kernel);
|
||||
if (ret) {
|
||||
pr_err("igc caching failed ret %d", ret);
|
||||
goto igc_config_exit;
|
||||
} else
|
||||
goto igc_set_dirty;
|
||||
}
|
||||
if (copy_from_kernel) {
|
||||
memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
|
||||
config->c0_c1_data, config->len * sizeof(u32));
|
||||
|
@ -2969,6 +2996,7 @@ int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config,
|
|||
&mdss_pp_res->igc_lut_c0c1[disp_num][0];
|
||||
mdss_pp_res->igc_disp_cfg[disp_num].c2_data =
|
||||
&mdss_pp_res->igc_lut_c2[disp_num][0];
|
||||
igc_set_dirty:
|
||||
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_IGC;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,9 @@ struct mdp_pp_driver_ops {
|
|||
};
|
||||
|
||||
struct mdss_pp_res_type_v1_7 {
|
||||
u32 igc_table_c0_c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
|
||||
u32 igc_table_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
|
||||
struct mdp_igc_lut_data_v1_7 igc_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 pcc_v17_data[MDSS_BLOCK_DISP_NUM];
|
||||
};
|
||||
|
|
|
@ -285,3 +285,112 @@ int pp_pcc_cache_params(struct mdp_pcc_cfg_data *config,
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pp_igc_lut_cache_params_v1_7(struct mdp_igc_lut_data *config,
|
||||
struct mdss_pp_res_type *mdss_pp_res,
|
||||
u32 copy_from_kernel)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mdss_pp_res_type_v1_7 *res_cache;
|
||||
struct mdp_igc_lut_data_v1_7 *v17_cache_data, v17_usr_config;
|
||||
u32 disp_num;
|
||||
if (!config || !mdss_pp_res) {
|
||||
pr_err("invalid param config %p pp_res %p\n",
|
||||
config, mdss_pp_res);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
|
||||
(config->block >= MDP_BLOCK_MAX)) {
|
||||
pr_err("invalid config block %d\n", config->block);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!mdss_pp_res->pp_data_res) {
|
||||
pr_err("invalid pp_data_res %p\n", mdss_pp_res->pp_data_res);
|
||||
return -EINVAL;
|
||||
}
|
||||
res_cache = mdss_pp_res->pp_data_res;
|
||||
if (config->ops & MDP_PP_OPS_READ) {
|
||||
pr_err("read op is not supported\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
|
||||
mdss_pp_res->igc_disp_cfg[disp_num] = *config;
|
||||
v17_cache_data = &res_cache->igc_v17_data[disp_num];
|
||||
mdss_pp_res->igc_disp_cfg[disp_num].cfg_payload =
|
||||
(void *) v17_cache_data;
|
||||
if (copy_from_user(&v17_usr_config, config->cfg_payload,
|
||||
sizeof(v17_usr_config))) {
|
||||
pr_err("failed to copy igc config\n");
|
||||
ret = -EFAULT;
|
||||
goto igc_config_exit;
|
||||
}
|
||||
if (!(config->ops & MDP_PP_OPS_WRITE)) {
|
||||
pr_debug("op for gamut %d\n", config->ops);
|
||||
goto igc_config_exit;
|
||||
}
|
||||
if (v17_usr_config.len != IGC_LUT_ENTRIES) {
|
||||
pr_err("Invalid table size %d exp %d\n",
|
||||
v17_usr_config.len, IGC_LUT_ENTRIES);
|
||||
ret = -EINVAL;
|
||||
goto igc_config_exit;
|
||||
}
|
||||
memcpy(v17_cache_data, &v17_usr_config,
|
||||
sizeof(v17_usr_config));
|
||||
v17_cache_data->c0_c1_data =
|
||||
&res_cache->igc_table_c0_c1[disp_num][0];
|
||||
v17_cache_data->c2_data =
|
||||
&res_cache->igc_table_c2[disp_num][0];
|
||||
if (copy_from_kernel) {
|
||||
memcpy(v17_cache_data->c0_c1_data,
|
||||
v17_usr_config.c0_c1_data,
|
||||
v17_usr_config.len * sizeof(u32));
|
||||
memcpy(v17_cache_data->c2_data, v17_usr_config.c2_data,
|
||||
v17_usr_config.len * sizeof(u32));
|
||||
} else {
|
||||
ret = copy_from_user(v17_cache_data->c0_c1_data,
|
||||
v17_usr_config.c0_c1_data,
|
||||
v17_usr_config.len * sizeof(u32));
|
||||
if (ret) {
|
||||
pr_err("copy from user failed for c0_c1_data size %zd ret %d\n",
|
||||
v17_usr_config.len * sizeof(u32), ret);
|
||||
ret = -EFAULT;
|
||||
goto igc_config_exit;
|
||||
}
|
||||
ret = copy_from_user(v17_cache_data->c2_data,
|
||||
v17_usr_config.c2_data,
|
||||
v17_usr_config.len * sizeof(u32));
|
||||
if (ret) {
|
||||
pr_err("copy from user failed for c2_data size %zd ret %d\n",
|
||||
v17_usr_config.len * sizeof(u32), ret);
|
||||
ret = -EFAULT;
|
||||
goto igc_config_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
igc_config_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
|
||||
struct mdss_pp_res_type *mdss_pp_res,
|
||||
u32 copy_from_kernel)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!config || !mdss_pp_res) {
|
||||
pr_err("invalid param config %p pp_res %p\n",
|
||||
config, mdss_pp_res);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (config->version) {
|
||||
case mdp_igc_v1_7:
|
||||
ret = pp_igc_lut_cache_params_v1_7(config, mdss_pp_res,
|
||||
copy_from_kernel);
|
||||
break;
|
||||
default:
|
||||
pr_err("unsupported igc version %d\n",
|
||||
config->version);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -21,4 +21,8 @@ int pp_gamut_cache_params(struct mdp_gamut_cfg_data *config,
|
|||
int pp_pcc_cache_params(struct mdp_pcc_cfg_data *config,
|
||||
struct mdss_pp_res_type *mdss_pp_res);
|
||||
|
||||
int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
|
||||
struct mdss_pp_res_type *mdss_pp_res,
|
||||
u32 copy_from_kernel);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define PCC_CONST_COEFF_MASK 0xFFFF
|
||||
#define PCC_COEFF_MASK 0x3FFFF
|
||||
|
||||
|
||||
#define GAMUT_OP_MODE_OFF 0
|
||||
#define GAMUT_TABLE_INDEX 4
|
||||
#define GAMUT_TABLE_UPPER_R 8
|
||||
|
@ -50,6 +51,17 @@
|
|||
#define GAMUT_FINE_INDEX 0
|
||||
#define GAMUT_ENABLE BIT(0)
|
||||
|
||||
#define IGC_MASK_MAX 3
|
||||
#define IGC_C0_LUT 0
|
||||
#define IGC_RGB_C0_LUT 0xC
|
||||
#define IGC_DMA_C0_LUT 0x18
|
||||
#define IGC_CONFIG_MASK(n) \
|
||||
((((1 << (IGC_MASK_MAX + 1)) - 1) & ~(1 << n)) << 28)
|
||||
#define IGC_INDEX_UPDATE BIT(25)
|
||||
#define IGC_INDEX_VALUE_UPDATE (BIT(24) | IGC_INDEX_UPDATE)
|
||||
#define IGC_DATA_MASK (BIT(12) - 1)
|
||||
#define IGC_DSPP_OP_MODE_EN BIT(0)
|
||||
|
||||
static struct mdss_pp_res_type_v1_7 config_data;
|
||||
|
||||
static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
|
||||
|
@ -68,6 +80,12 @@ static int pp_pcc_set_config(char __iomem *base_addr,
|
|||
static int pp_pcc_get_config(char __iomem *base_addr, void *cfg_data,
|
||||
u32 block_type, u32 disp_num);
|
||||
|
||||
static int pp_igc_set_config(char __iomem *base_addr,
|
||||
struct pp_sts_type *pp_sts, void *cfg_data,
|
||||
u32 block_type);
|
||||
static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
|
||||
u32 block_type, u32 disp_num);
|
||||
|
||||
void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
|
||||
{
|
||||
if (!ops) {
|
||||
|
@ -76,8 +94,8 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
|
|||
}
|
||||
|
||||
/* IGC ops */
|
||||
ops->pp_ops[IGC].pp_set_config = NULL;
|
||||
ops->pp_ops[IGC].pp_get_config = NULL;
|
||||
ops->pp_ops[IGC].pp_set_config = pp_igc_set_config;
|
||||
ops->pp_ops[IGC].pp_get_config = pp_igc_get_config;
|
||||
|
||||
/* PCC ops */
|
||||
ops->pp_ops[PCC].pp_set_config = pp_pcc_set_config;
|
||||
|
@ -124,7 +142,23 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
|
|||
pr_err("Invalid pp_sts %p or opmode %p\n", pp_sts, opmode);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (location) {
|
||||
case SSPP_RGB:
|
||||
break;
|
||||
case SSPP_DMA:
|
||||
break;
|
||||
case SSPP_VIG:
|
||||
break;
|
||||
case DSPP:
|
||||
if (pp_sts_is_enabled(pp_sts->igc_sts, side))
|
||||
*opmode |= IGC_DSPP_OP_MODE_EN;
|
||||
break;
|
||||
case LM:
|
||||
break;
|
||||
default:
|
||||
pr_err("Invalid block type %d\n", location);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -517,3 +551,174 @@ static int pp_pcc_get_config(char __iomem *base_addr, void *cfg_data,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_igc_set_config(char __iomem *base_addr,
|
||||
struct pp_sts_type *pp_sts, void *cfg_data,
|
||||
u32 block_type)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
struct mdp_igc_lut_data *lut_cfg_data = NULL;
|
||||
struct mdp_igc_lut_data_v1_7 *lut_data = NULL;
|
||||
char __iomem *c0 = NULL, *c1 = NULL, *c2 = NULL;
|
||||
u32 data;
|
||||
|
||||
if (!base_addr || !cfg_data || !pp_sts) {
|
||||
pr_err("invalid params base_addr %p cfg_data %p pp_sts_type %p\n",
|
||||
base_addr, cfg_data, pp_sts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lut_cfg_data = (struct mdp_igc_lut_data *) cfg_data;
|
||||
if (lut_cfg_data->version != mdp_igc_v1_7 ||
|
||||
!lut_cfg_data->cfg_payload) {
|
||||
pr_err("invalid igc version %d payload %p\n",
|
||||
lut_cfg_data->version, lut_cfg_data->cfg_payload);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!(lut_cfg_data->ops & ~(MDP_PP_OPS_READ))) {
|
||||
pr_err("only read ops set for lut\n");
|
||||
return ret;
|
||||
}
|
||||
if (lut_cfg_data->block > IGC_MASK_MAX) {
|
||||
pr_err("invalid mask value for IGC %d", lut_cfg_data->block);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!(lut_cfg_data->ops & MDP_PP_OPS_WRITE)) {
|
||||
pr_debug("non write ops set %d\n", lut_cfg_data->ops);
|
||||
goto bail_out;
|
||||
}
|
||||
lut_data = lut_cfg_data->cfg_payload;
|
||||
if (lut_data->len != IGC_LUT_ENTRIES || !lut_data->c0_c1_data ||
|
||||
!lut_data->c2_data) {
|
||||
pr_err("invalid lut len %d c0_c1_data %p c2_data %p\n",
|
||||
lut_data->len, lut_data->c0_c1_data, lut_data->c2_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (block_type) {
|
||||
case SSPP_RGB:
|
||||
c0 = base_addr + IGC_RGB_C0_LUT;
|
||||
break;
|
||||
case SSPP_DMA:
|
||||
c0 = base_addr + IGC_DMA_C0_LUT;
|
||||
break;
|
||||
case SSPP_VIG:
|
||||
case DSPP:
|
||||
c0 = base_addr + IGC_C0_LUT;
|
||||
break;
|
||||
default:
|
||||
pr_err("Invalid block type %d\n", block_type);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
pr_err("igc table not updated ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
c1 = c0 + 4;
|
||||
c2 = c1 + 4;
|
||||
data = IGC_INDEX_UPDATE | IGC_CONFIG_MASK(lut_cfg_data->block);
|
||||
pr_debug("data %x block type %d mask %x\n",
|
||||
data, lut_cfg_data->block,
|
||||
IGC_CONFIG_MASK(lut_cfg_data->block));
|
||||
writel_relaxed((lut_data->c0_c1_data[0] & IGC_DATA_MASK) | data, c0);
|
||||
writel_relaxed(((lut_data->c0_c1_data[0] >> 16)
|
||||
& IGC_DATA_MASK) | data, c1);
|
||||
writel_relaxed((lut_data->c2_data[0] & IGC_DATA_MASK) | data, c2);
|
||||
data &= ~IGC_INDEX_UPDATE;
|
||||
/* update the index for c0, c1 , c2 */
|
||||
for (i = 1; i < IGC_LUT_ENTRIES; i++) {
|
||||
writel_relaxed((lut_data->c0_c1_data[i] & IGC_DATA_MASK)
|
||||
| data, c0);
|
||||
writel_relaxed(((lut_data->c0_c1_data[i] >> 16)
|
||||
& IGC_DATA_MASK) | data, c1);
|
||||
writel_relaxed((lut_data->c2_data[i] & IGC_DATA_MASK)
|
||||
| data, c2);
|
||||
}
|
||||
bail_out:
|
||||
if (!ret) {
|
||||
if (lut_cfg_data->ops & MDP_PP_OPS_DISABLE)
|
||||
pp_sts->igc_sts &= ~PP_STS_ENABLE;
|
||||
else if (lut_cfg_data->ops & MDP_PP_OPS_ENABLE)
|
||||
pp_sts->igc_sts |= PP_STS_ENABLE;
|
||||
pp_sts_set_split_bits(&pp_sts->igc_sts,
|
||||
lut_cfg_data->ops);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
|
||||
u32 block_type, u32 disp_num)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
struct mdp_igc_lut_data *lut_cfg_data = NULL;
|
||||
struct mdp_igc_lut_data_v1_7 *lut_data = NULL;
|
||||
char __iomem *c1 = NULL, *c2 = NULL;
|
||||
u32 *c0c1_data = NULL, *c2_data = NULL;
|
||||
u32 data = 0, sz = 0;
|
||||
|
||||
if (!base_addr || !cfg_data || block_type != DSPP) {
|
||||
pr_err("invalid params base_addr %p cfg_data %p block_type %d\n",
|
||||
base_addr, cfg_data, block_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
lut_cfg_data = (struct mdp_igc_lut_data *) cfg_data;
|
||||
if (!(lut_cfg_data->ops & MDP_PP_OPS_READ)) {
|
||||
pr_err("read ops not set for lut ops %d\n", lut_cfg_data->ops);
|
||||
return ret;
|
||||
}
|
||||
if (lut_cfg_data->version != mdp_igc_v1_7 ||
|
||||
!lut_cfg_data->cfg_payload ||
|
||||
lut_cfg_data->block > IGC_MASK_MAX) {
|
||||
pr_err("invalid igc version %d payload %p block %d\n",
|
||||
lut_cfg_data->version, lut_cfg_data->cfg_payload,
|
||||
lut_cfg_data->block);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
lut_data = lut_cfg_data->cfg_payload;
|
||||
if (lut_data->len != IGC_LUT_ENTRIES) {
|
||||
pr_err("invalid lut len %d\n", lut_data->len);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
sz = IGC_LUT_ENTRIES * sizeof(u32);
|
||||
if (!access_ok(VERIFY_WRITE, lut_data->c0_c1_data, sz) ||
|
||||
(!access_ok(VERIFY_WRITE, lut_data->c2_data, sz))) {
|
||||
pr_err("invalid lut address for sz %d\n", sz);
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
/* Allocate for c0c1 and c2 tables */
|
||||
c0c1_data = kzalloc(sz * 2, GFP_KERNEL);
|
||||
if (!c0c1_data) {
|
||||
pr_err("allocation failed for c0c1 size %d\n", sz * 2);
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
c2_data = &c0c1_data[IGC_LUT_ENTRIES];
|
||||
data = IGC_INDEX_VALUE_UPDATE | IGC_CONFIG_MASK(lut_cfg_data->block);
|
||||
pr_debug("data %x block type %d mask %x\n",
|
||||
data, lut_cfg_data->block,
|
||||
IGC_CONFIG_MASK(lut_cfg_data->block));
|
||||
c1 = base_addr + 4;
|
||||
c2 = c1 + 4;
|
||||
writel_relaxed(data, base_addr);
|
||||
writel_relaxed(data, c1);
|
||||
writel_relaxed(data, c2);
|
||||
for (i = 0; i < IGC_LUT_ENTRIES; i++) {
|
||||
c0c1_data[i] = readl_relaxed(base_addr) & IGC_DATA_MASK;
|
||||
c0c1_data[i] |= (readl_relaxed(c1) & IGC_DATA_MASK) << 16;
|
||||
c2_data[i] = readl_relaxed(c2) & IGC_DATA_MASK;
|
||||
}
|
||||
if (copy_to_user(lut_data->c0_c1_data, c0c1_data, sz)) {
|
||||
pr_err("failed to copy the c0c1 data");
|
||||
ret = -EFAULT;
|
||||
}
|
||||
if (!ret && copy_to_user(lut_data->c2_data, c2_data, sz)) {
|
||||
pr_err("failed to copy the c2 data");
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(c0c1_data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -526,6 +526,18 @@ struct mdp_pa_v2_cfg_data {
|
|||
void *cfg_payload;
|
||||
};
|
||||
|
||||
enum {
|
||||
mdp_igc_v1_7 = 1,
|
||||
mdp_igc_vmax,
|
||||
};
|
||||
|
||||
enum {
|
||||
mdp_igc_rec601,
|
||||
mdp_igc_rec709,
|
||||
mdp_igc_custom,
|
||||
mdp_igc_mode_max,
|
||||
};
|
||||
|
||||
struct mdp_igc_lut_data {
|
||||
uint32_t block;
|
||||
uint32_t version;
|
||||
|
@ -536,6 +548,7 @@ struct mdp_igc_lut_data {
|
|||
};
|
||||
|
||||
struct mdp_igc_lut_data_v1_7 {
|
||||
uint32_t table_fmt;
|
||||
uint32_t len;
|
||||
uint32_t *c0_c1_data;
|
||||
uint32_t *c2_data;
|
||||
|
|
Loading…
Add table
Reference in a new issue