blob: ade3add298c3856dca03eb9f0b4f070a0a8d8df1 [file] [log] [blame]
/*
* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_pp.h"
#include "mdss_mdp_pp_cache_config.h"
#define IGC_C1_SHIFT 16
static u32 pp_igc_601[IGC_LUT_ENTRIES] = {
0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 23,
25, 27, 29, 31, 33, 35, 37, 40, 42, 45, 48, 50, 53, 56, 59, 62,
66, 69, 72, 76, 79, 83, 87, 91, 95, 99, 103, 107, 112, 116, 121,
126, 131, 136, 141, 146, 151, 156, 162, 168, 173, 179, 185, 191,
197, 204, 210, 216, 223, 230, 237, 244, 251, 258, 265, 273, 280,
288, 296, 304, 312, 320, 329, 337, 346, 354, 363, 372, 381, 390,
400, 409, 419, 428, 438, 448, 458, 469, 479, 490, 500, 511, 522,
533, 544, 555, 567, 578, 590, 602, 614, 626, 639, 651, 664, 676,
689, 702, 715, 728, 742, 755, 769, 783, 797, 811, 825, 840, 854,
869, 884, 899, 914, 929, 945, 960, 976, 992, 1008, 1024, 1041,
1057, 1074, 1091, 1108, 1125, 1142, 1159, 1177, 1195, 1213, 1231,
1249, 1267, 1286, 1304, 1323, 1342, 1361, 1381, 1400, 1420, 1440,
1459, 1480, 1500, 1520, 1541, 1562, 1582, 1603, 1625, 1646, 1668,
1689, 1711, 1733, 1755, 1778, 1800, 1823, 1846, 1869, 1892, 1916,
1939, 1963, 1987, 2011, 2035, 2059, 2084, 2109, 2133, 2159, 2184,
2209, 2235, 2260, 2286, 2312, 2339, 2365, 2392, 2419, 2446, 2473,
2500, 2527, 2555, 2583, 2611, 2639, 2668, 2696, 2725, 2754, 2783,
2812, 2841, 2871, 2901, 2931, 2961, 2991, 3022, 3052, 3083, 3114,
3146, 3177, 3209, 3240, 3272, 3304, 3337, 3369, 3402, 3435, 3468,
3501, 3535, 3568, 3602, 3636, 3670, 3705, 3739, 3774, 3809, 3844,
3879, 3915, 3950, 3986, 4022, 4059, 4095,
};
static u32 pp_igc_709[IGC_LUT_ENTRIES] = {
0, 4, 7, 11, 14, 18, 21, 25, 29, 32, 36, 39, 43, 46, 50, 54, 57,
61, 64, 68, 71, 75, 78, 82, 86, 90, 94, 98, 102, 107, 111, 115,
120, 125, 130, 134, 139, 145, 150, 155, 161, 166, 172, 177, 183,
189, 195, 201, 208, 214, 220, 227, 234, 240, 247, 254, 261, 269,
276, 283, 291, 298, 306, 314, 322, 330, 338, 347, 355, 364, 372,
381, 390, 399, 408, 417, 426, 436, 445, 455, 465, 474, 484, 495,
505, 515, 525, 536, 547, 558, 568, 579, 591, 602, 613, 625, 636,
648, 660, 672, 684, 696, 708, 721, 733, 746, 759, 772, 785, 798,
811, 825, 838, 852, 865, 879, 893, 907, 922, 936, 950, 965, 980,
995, 1010, 1025, 1040, 1055, 1071, 1086, 1102, 1118, 1134, 1150,
1166, 1183, 1199, 1216, 1232, 1249, 1266, 1283, 1300, 1318, 1335,
1353, 1370, 1388, 1406, 1424, 1443, 1461, 1479, 1498, 1517, 1536,
1555, 1574, 1593, 1612, 1632, 1652, 1671, 1691, 1711, 1731, 1752,
1772, 1793, 1813, 1834, 1855, 1876, 1897, 1919, 1940, 1962, 1984,
2005, 2027, 2050, 2072, 2094, 2117, 2139, 2162, 2185, 2208, 2231,
2255, 2278, 2302, 2325, 2349, 2373, 2397, 2422, 2446, 2471, 2495,
2520, 2545, 2570, 2595, 2621, 2646, 2672, 2697, 2723, 2749, 2775,
2802, 2828, 2855, 2881, 2908, 2935, 2962, 2990, 3017, 3044, 3072,
3100, 3128, 3156, 3184, 3212, 3241, 3270, 3298, 3327, 3356, 3385,
3415, 3444, 3474, 3503, 3533, 3563, 3594, 3624, 3654, 3685, 3716,
3746, 3777, 3808, 3840, 3871, 3903, 3934, 3966, 3998, 4030, 4063,
4095,
};
static u32 pp_igc_srgb[IGC_LUT_ENTRIES] = {
0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 23,
25, 27, 29, 31, 33, 35, 37, 40, 42, 45, 48, 50, 53, 56, 59, 62,
66, 69, 72, 76, 79, 83, 87, 91, 95, 99, 103, 107, 112, 116, 121,
126, 131, 136, 141, 146, 151, 156, 162, 168, 173, 179, 185, 191,
197, 204, 210, 216, 223, 230, 237, 244, 251, 258, 265, 273, 280,
288, 296, 304, 312, 320, 329, 337, 346, 354, 363, 372, 381, 390,
400, 409, 419, 428, 438, 448, 458, 469, 479, 490, 500, 511, 522,
533, 544, 555, 567, 578, 590, 602, 614, 626, 639, 651, 664, 676,
689, 702, 715, 728, 742, 755, 769, 783, 797, 811, 825, 840, 854,
869, 884, 899, 914, 929, 945, 960, 976, 992, 1008, 1024, 1041,
1057, 1074, 1091, 1108, 1125, 1142, 1159, 1177, 1195, 1213, 1231, 1249,
1267, 1286, 1304, 1323, 1342, 1361, 1381, 1400, 1420, 1440, 1459, 1480,
1500, 1520, 1541, 1562, 1582, 1603, 1625, 1646, 1668, 1689, 1711, 1733,
1755, 1778, 1800, 1823, 1846, 1869, 1892, 1916, 1939, 1963, 1987, 2011,
2035, 2059, 2084, 2109, 2133, 2159, 2184, 2209, 2235, 2260, 2286, 2312,
2339, 2365, 2392, 2419, 2446, 2473, 2500, 2527, 2555, 2583, 2611, 2639,
2668, 2696, 2725, 2754, 2783, 2812, 2841, 2871, 2901, 2931, 2961, 2991,
3022, 3052, 3083, 3114, 3146, 3177, 3209, 3240, 3272, 3304, 3337, 3369,
3402, 3435, 3468, 3501, 3535, 3568, 3602, 3636, 3670, 3705, 3739, 3774,
3809, 3844, 3879, 3915, 3950, 3986, 4022, 4059, 4095
};
static int pp_hist_lut_cache_params_v1_7(struct mdp_hist_lut_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
u32 disp_num;
struct mdss_pp_res_type_v1_7 *res_cache = NULL;
struct mdp_hist_lut_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
int ret = 0;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\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_v1_7) {
pr_err("invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (config->ops & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -EINVAL;
}
{
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
v17_cache_data = &res_cache->hist_lut_v17_data[disp_num];
mdss_pp_res->enhist_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 v17 hist_lut\n");
ret = -EFAULT;
return ret;
}
if ((config->ops & MDP_PP_OPS_DISABLE)) {
pr_debug("disable hist_lut\n");
ret = 0;
return ret;
}
memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config));
if (v17_usr_config.len != ENHIST_LUT_ENTRIES) {
pr_err("Invalid table size %d exp %d\n",
v17_usr_config.len, ENHIST_LUT_ENTRIES);
ret = -EINVAL;
return ret;
}
v17_cache_data->data = &res_cache->hist_lut[disp_num][0];
if (copy_from_user(v17_cache_data->data, v17_usr_config.data,
v17_usr_config.len * sizeof(u32))) {
pr_err("failed to copy v17 hist_lut->data\n");
ret = -EFAULT;
return ret;
}
}
return ret;
}
static int pp_hist_lut_cache_params_pipe_v1_7(struct mdp_hist_lut_data *config,
struct mdss_mdp_pipe *pipe)
{
struct mdp_hist_lut_data_v1_7 *hist_lut_cache_data;
struct mdp_hist_lut_data_v1_7 hist_lut_usr_config;
int ret = 0;
if (!config || !pipe) {
pr_err("Invalid param config %pK pipe %pK\n",
config, pipe);
return -EINVAL;
}
if (config->ops & MDP_PP_OPS_DISABLE) {
pr_debug("Disable Hist LUT on pipe %d\n", pipe->num);
goto hist_lut_cache_pipe_exit;
}
if (config->ops & MDP_PP_OPS_READ) {
pr_err("Read op is not supported\n");
return -EINVAL;
}
if (!config->cfg_payload) {
pr_err("Hist LUT config payload invalid\n");
return -EINVAL;
}
if (copy_from_user(&hist_lut_usr_config,
(void __user *) config->cfg_payload,
sizeof(hist_lut_usr_config))) {
pr_err("failed to copy hist lut config\n");
return -EFAULT;
}
hist_lut_cache_data = pipe->pp_res.hist_lut_cfg_payload;
if (!hist_lut_cache_data) {
hist_lut_cache_data = kzalloc(
sizeof(struct mdp_hist_lut_data_v1_7),
GFP_KERNEL);
if (!hist_lut_cache_data) {
pr_err("failed to allocate cache_data\n");
ret = -ENOMEM;
goto hist_lut_cache_pipe_exit;
} else
pipe->pp_res.hist_lut_cfg_payload = hist_lut_cache_data;
}
*hist_lut_cache_data = hist_lut_usr_config;
if (hist_lut_cache_data->len != ENHIST_LUT_ENTRIES) {
pr_err("Invalid Hist LUT length %d\n",
hist_lut_cache_data->len);
ret = -EINVAL;
goto hist_lut_cache_pipe_exit;
}
if (copy_from_user(pipe->pp_res.hist_lut,
hist_lut_usr_config.data,
sizeof(uint32_t) * hist_lut_cache_data->len)) {
pr_err("Failed to copy usr Hist LUT data\n");
ret = -EFAULT;
goto hist_lut_cache_pipe_exit;
}
hist_lut_cache_data->data = pipe->pp_res.hist_lut;
hist_lut_cache_pipe_exit:
if (ret || (config->ops & MDP_PP_OPS_DISABLE)) {
kfree(pipe->pp_res.hist_lut_cfg_payload);
pipe->pp_res.hist_lut_cfg_payload = NULL;
}
pipe->pp_cfg.hist_lut_cfg.cfg_payload =
pipe->pp_res.hist_lut_cfg_payload;
return ret;
}
int pp_hist_lut_cache_params(struct mdp_hist_lut_data *config,
struct mdp_pp_cache_res *res_cache)
{
int ret = 0;
if (!config || !res_cache) {
pr_err("invalid param config %pK res_cache %pK\n",
config, res_cache);
return -EINVAL;
}
if (res_cache->block != SSPP_VIG && res_cache->block != DSPP) {
pr_err("invalid block for Hist LUT %d\n", res_cache->block);
return -EINVAL;
}
if (!res_cache->mdss_pp_res && !res_cache->pipe_res) {
pr_err("NULL payload for block %d mdss_pp_res %pK pipe_res %pK\n",
res_cache->block, res_cache->mdss_pp_res,
res_cache->pipe_res);
return -EINVAL;
}
switch (config->version) {
case mdp_hist_lut_v1_7:
if (res_cache->block == DSPP) {
ret = pp_hist_lut_cache_params_v1_7(config,
res_cache->mdss_pp_res);
if (ret)
pr_err("failed to cache Hist LUT params for DSPP ret %d\n",
ret);
} else {
ret = pp_hist_lut_cache_params_pipe_v1_7(config,
res_cache->pipe_res);
if (ret)
pr_err("failed to cache Hist LUT params for SSPP ret %d\n",
ret);
}
break;
default:
pr_err("unsupported hist_lut version %d\n",
config->version);
ret = -EINVAL;
break;
}
return ret;
}
int pp_dither_cache_params_v1_7(struct mdp_dither_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res,
int copy_from_kernel)
{
u32 disp_num;
int ret = 0;
struct mdss_pp_res_type_v1_7 *res_cache = NULL;
struct mdp_dither_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\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_v1_7) {
pr_err("invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
pr_warn("Can't set both split bits\n");
return -EINVAL;
}
if (config->flags & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -ENOTSUPP;
}
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
if (config->flags & MDP_PP_OPS_DISABLE) {
pr_debug("disable dither\n");
ret = 0;
goto dither_config_exit;
}
if (!(config->flags & MDP_PP_OPS_WRITE)) {
pr_debug("op for dither %d\n", config->flags);
goto dither_config_exit;
}
v17_cache_data = &res_cache->dither_v17_data[disp_num];
mdss_pp_res->dither_disp_cfg[disp_num].cfg_payload =
(void *)v17_cache_data;
if (copy_from_kernel) {
memcpy(v17_cache_data, config->cfg_payload,
sizeof(struct mdp_dither_data_v1_7));
} else {
if (copy_from_user(&v17_usr_config, config->cfg_payload,
sizeof(v17_usr_config))) {
pr_err("failed to copy v17 dither\n");
ret = -EFAULT;
goto dither_config_exit;
}
memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config));
}
if (v17_cache_data->len &&
v17_cache_data->len != MDP_DITHER_DATA_V1_7_SZ) {
pr_err("invalid dither len %d expected %d\n",
v17_cache_data->len, MDP_DITHER_DATA_V1_7_SZ);
ret = -EINVAL;
}
dither_config_exit:
return ret;
}
int pp_dither_cache_params(struct mdp_dither_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res,
int copy_from_kernel)
{
int ret = 0;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\n",
config, mdss_pp_res);
return -EINVAL;
}
switch (config->version) {
case mdp_dither_v1_7:
ret = pp_dither_cache_params_v1_7(config, mdss_pp_res,
copy_from_kernel);
break;
default:
pr_err("unsupported dither version %d\n",
config->version);
break;
}
return ret;
}
static int pp_gamut_cache_params_v1_7(struct mdp_gamut_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
u32 disp_num, tbl_sz;
struct mdss_pp_res_type_v1_7 *res_cache;
struct mdp_gamut_data_v1_7 *v17_cache_data, v17_usr_config;
u32 gamut_size = 0, scal_coff_size = 0, sz = 0, index = 0;
u32 *tbl_gamut = NULL;
int ret = 0, i = 0;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\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_v1_7) {
pr_err("invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (config->flags & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -EINVAL;
}
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
/* Copy top level gamut cfg struct into PP res cache */
memcpy(&mdss_pp_res->gamut_disp_cfg[disp_num], config,
sizeof(struct mdp_gamut_cfg_data));
v17_cache_data = &res_cache->gamut_v17_data[disp_num];
mdss_pp_res->gamut_disp_cfg[disp_num].cfg_payload =
(void *) v17_cache_data;
tbl_gamut = v17_cache_data->c0_data[0];
if ((config->flags & MDP_PP_OPS_DISABLE)) {
pr_debug("disable gamut\n");
ret = 0;
goto gamut_config_exit;
}
if (copy_from_user(&v17_usr_config, config->cfg_payload,
sizeof(v17_usr_config))) {
pr_err("failed to copy v17 gamut\n");
ret = -EFAULT;
goto gamut_config_exit;
}
if (v17_usr_config.mode != mdp_gamut_coarse_mode &&
v17_usr_config.mode != mdp_gamut_fine_mode) {
pr_err("invalid gamut mode %d\n", v17_usr_config.mode);
return -EINVAL;
}
if (!(config->flags & MDP_PP_OPS_WRITE)) {
pr_debug("op for gamut %d\n", config->flags);
goto gamut_config_exit;
}
tbl_sz = (v17_usr_config.mode == mdp_gamut_fine_mode) ?
MDP_GAMUT_TABLE_V1_7_SZ :
MDP_GAMUT_TABLE_V1_7_COARSE_SZ;
v17_cache_data->mode = v17_usr_config.mode;
v17_cache_data->map_en = v17_usr_config.map_en;
/* sanity check for sizes */
for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
if (v17_usr_config.tbl_size[i] != tbl_sz) {
pr_err("invalid tbl size %d exp %d tbl index %d mode %d\n",
v17_usr_config.tbl_size[i], tbl_sz, i,
v17_usr_config.mode);
ret = -EINVAL;
goto gamut_config_exit;
}
gamut_size += v17_usr_config.tbl_size[i];
if (i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM)
continue;
if (v17_usr_config.tbl_scale_off_sz[i] !=
MDP_GAMUT_SCALE_OFF_SZ) {
pr_err("invalid scale size %d exp %d scale index %d mode %d\n",
v17_usr_config.tbl_scale_off_sz[i],
MDP_GAMUT_SCALE_OFF_SZ, i,
v17_usr_config.mode);
ret = -EINVAL;
goto gamut_config_exit;
}
scal_coff_size += v17_usr_config.tbl_scale_off_sz[i];
}
/* gamut size should be accounted for c0, c1c2 table */
sz = gamut_size * 2 + scal_coff_size;
if (sz > GAMUT_TOTAL_TABLE_SIZE_V1_7) {
pr_err("Invalid table size act %d max %d\n",
sz, GAMUT_TOTAL_TABLE_SIZE_V1_7);
ret = -EINVAL;
goto gamut_config_exit;
}
/* Allocate for fine mode other modes will fit */
if (!tbl_gamut)
tbl_gamut = vmalloc(GAMUT_TOTAL_TABLE_SIZE_V1_7 *
sizeof(u32));
if (!tbl_gamut) {
ret = -ENOMEM;
goto gamut_config_exit;
}
index = 0;
for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
ret = copy_from_user(&tbl_gamut[index],
v17_usr_config.c0_data[i],
(sizeof(u32) * v17_usr_config.tbl_size[i]));
if (ret) {
pr_err("copying c0 table %d from userspace failed size %zd ret %d\n",
i, (sizeof(u32) *
v17_usr_config.tbl_size[i]), ret);
ret = -EFAULT;
goto gamut_memory_free_exit;
}
v17_cache_data->c0_data[i] = &tbl_gamut[index];
v17_cache_data->tbl_size[i] =
v17_usr_config.tbl_size[i];
index += v17_usr_config.tbl_size[i];
ret = copy_from_user(&tbl_gamut[index],
v17_usr_config.c1_c2_data[i],
(sizeof(u32) * v17_usr_config.tbl_size[i]));
if (ret) {
pr_err("copying c1_c2 table %d from userspace failed size %zd ret %d\n",
i, (sizeof(u32) *
v17_usr_config.tbl_size[i]), ret);
ret = -EINVAL;
goto gamut_memory_free_exit;
}
v17_cache_data->c1_c2_data[i] = &tbl_gamut[index];
index += v17_usr_config.tbl_size[i];
}
for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) {
ret = copy_from_user(&tbl_gamut[index],
v17_usr_config.scale_off_data[i],
(sizeof(u32) *
v17_usr_config.tbl_scale_off_sz[i]));
if (ret) {
pr_err("copying scale offset table %d from userspace failed size %zd ret %d\n",
i, (sizeof(u32) *
v17_usr_config.tbl_scale_off_sz[i]),
ret);
ret = -EFAULT;
goto gamut_memory_free_exit;
}
v17_cache_data->tbl_scale_off_sz[i] =
v17_usr_config.tbl_scale_off_sz[i];
v17_cache_data->scale_off_data[i] = &tbl_gamut[index];
index += v17_usr_config.tbl_scale_off_sz[i];
}
gamut_config_exit:
return ret;
gamut_memory_free_exit:
vfree(tbl_gamut);
for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
v17_cache_data->c0_data[i] = NULL;
v17_cache_data->c1_c2_data[i] = NULL;
v17_cache_data->tbl_size[i] = 0;
if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM) {
v17_cache_data->scale_off_data[i] = NULL;
v17_cache_data->tbl_scale_off_sz[i] = 0;
}
}
return ret;
}
int pp_gamut_cache_params(struct mdp_gamut_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
int ret = 0;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\n",
config, mdss_pp_res);
return -EINVAL;
}
switch (config->version) {
case mdp_gamut_v1_7:
ret = pp_gamut_cache_params_v1_7(config, mdss_pp_res);
break;
default:
pr_err("unsupported gamut version %d\n",
config->version);
ret = -EINVAL;
break;
}
return ret;
}
static int pp_pcc_cache_params_pipe_v1_7(struct mdp_pcc_cfg_data *config,
struct mdss_mdp_pipe *pipe)
{
struct mdp_pcc_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
if (!pipe || !config) {
pr_err("invalid params pipe %pK config %pK\n", pipe, config);
return -EINVAL;
}
if (config->ops & MDP_PP_OPS_DISABLE) {
pr_debug("disable ops set cleanup payload\n");
goto cleanup;
}
if (config->ops & MDP_PP_OPS_READ) {
pr_err("read ops not supported\n");
return -EINVAL;
}
if (!config->cfg_payload) {
pr_err("PCC config payload invalid\n");
return -EINVAL;
}
if (copy_from_user(&v17_usr_config,
(void __user *) config->cfg_payload,
sizeof(v17_usr_config))) {
pr_err("failed to copy pcc config\n");
return -EFAULT;
}
if (!(config->ops & MDP_PP_OPS_WRITE)) {
pr_debug("write ops not set value of flag is %d\n",
config->ops);
goto cleanup;
}
v17_cache_data = pipe->pp_res.pcc_cfg_payload;
if (!v17_cache_data) {
v17_cache_data = kzalloc(sizeof(struct mdp_pcc_data_v1_7),
GFP_KERNEL);
pipe->pp_res.pcc_cfg_payload = v17_cache_data;
}
if (!v17_cache_data) {
pr_err("failed to allocate the pcc cache data\n");
return -ENOMEM;
}
memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config));
pipe->pp_cfg.pcc_cfg_data.cfg_payload = v17_cache_data;
cleanup:
if (config->ops & MDP_PP_OPS_DISABLE) {
kfree(pipe->pp_res.pcc_cfg_payload);
pipe->pp_res.pcc_cfg_payload = NULL;
pipe->pp_cfg.pcc_cfg_data.cfg_payload = NULL;
}
return 0;
}
static int pp_pcc_cache_params_v1_7(struct mdp_pcc_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
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;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\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_v1_7) {
pr_err("invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (config->ops & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -EINVAL;
}
{
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->pcc_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 v17 pcc\n");
ret = -EFAULT;
goto pcc_config_exit;
}
if ((config->ops & MDP_PP_OPS_DISABLE)) {
pr_debug("disable pcc\n");
ret = 0;
goto pcc_config_exit;
}
if (!(config->ops & MDP_PP_OPS_WRITE)) {
pr_debug("op for pcc %d\n", config->ops);
goto pcc_config_exit;
}
memcpy(v17_cache_data, &v17_usr_config, sizeof(v17_usr_config));
}
pcc_config_exit:
return ret;
}
int pp_pcc_cache_params(struct mdp_pcc_cfg_data *config,
struct mdp_pp_cache_res *res_cache)
{
int ret = 0;
if (!config || !res_cache) {
pr_err("invalid param config %pK pp_res %pK\n",
config, res_cache);
return -EINVAL;
}
if (res_cache->block < SSPP_RGB || res_cache->block > DSPP) {
pr_err("invalid block for PCC %d\n", res_cache->block);
return -EINVAL;
}
if (!res_cache->mdss_pp_res && !res_cache->pipe_res) {
pr_err("NULL payload for block %d mdss_pp_res %pK pipe_res %pK\n",
res_cache->block, res_cache->mdss_pp_res,
res_cache->pipe_res);
return -EINVAL;
}
switch (config->version) {
case mdp_pcc_v1_7:
if (res_cache->block == DSPP) {
ret = pp_pcc_cache_params_v1_7(config,
res_cache->mdss_pp_res);
if (ret)
pr_err("caching for DSPP failed for PCC ret %d\n",
ret);
} else {
ret = pp_pcc_cache_params_pipe_v1_7(config,
res_cache->pipe_res);
if (ret)
pr_err("caching for SSPP failed for PCC ret %d block %d\n",
ret, res_cache->block);
}
break;
default:
pr_err("unsupported pcc version %d\n",
config->version);
ret = -EINVAL;
break;
}
return ret;
}
static 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 %pK pp_res %pK\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_v1_7) {
pr_err("invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (config->ops & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -EINVAL;
}
{
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_kernel) {
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;
}
} else {
if (!config->cfg_payload) {
pr_err("can't copy config info NULL payload\n");
ret = -EINVAL;
goto igc_config_exit;
}
memcpy(&v17_usr_config, config->cfg_payload,
sizeof(v17_usr_config));
}
if (!(config->ops & MDP_PP_OPS_WRITE)) {
pr_debug("op for gamut %d\n", config->ops);
goto igc_config_exit;
}
if (copy_from_kernel && (!v17_usr_config.c0_c1_data ||
!v17_usr_config.c2_data)) {
pr_err("copy from kernel invalid params c0_c1_data %pK c2_data %pK\n",
v17_usr_config.c0_c1_data,
v17_usr_config.c2_data);
ret = -EINVAL;
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;
}
static int pp_igc_lut_cache_params_pipe_v1_7(struct mdp_igc_lut_data *config,
struct mdss_mdp_pipe *pipe,
u32 copy_from_kernel)
{
struct mdp_igc_lut_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
int ret = 0, fix_up = 0, i = 0;
if (!config || !pipe) {
pr_err("invalid param config %pK pipe %pK\n",
config, pipe);
return -EINVAL;
}
if (config->ops & MDP_PP_OPS_READ) {
pr_err("read op is not supported\n");
return -EINVAL;
}
if (!config->cfg_payload) {
pr_err("can't copy config info NULL payload\n");
ret = -EINVAL;
goto igc_config_exit;
}
if (copy_from_user(&v17_usr_config,
(void __user *) config->cfg_payload,
sizeof(v17_usr_config))) {
pr_err("failed to copy igc config\n");
return -EFAULT;
}
if (!(config->ops & MDP_PP_OPS_WRITE)) {
pr_debug("op for gamut %d\n", config->ops);
goto igc_config_exit;
}
switch (v17_usr_config.table_fmt) {
case mdp_igc_custom:
if (!v17_usr_config.c0_c1_data ||
!v17_usr_config.c2_data ||
v17_usr_config.len != IGC_LUT_ENTRIES) {
pr_err("invalid c0_c1data %pK c2_data %pK tbl len %d\n",
v17_usr_config.c0_c1_data,
v17_usr_config.c2_data,
v17_usr_config.len);
ret = -EINVAL;
goto igc_config_exit;
}
break;
case mdp_igc_rec709:
v17_usr_config.c0_c1_data = pp_igc_709;
v17_usr_config.c2_data = pp_igc_709;
v17_usr_config.len = IGC_LUT_ENTRIES;
copy_from_kernel = 1;
fix_up = 1;
break;
case mdp_igc_srgb:
v17_usr_config.c0_c1_data = pp_igc_srgb;
v17_usr_config.c2_data = pp_igc_srgb;
v17_usr_config.len = IGC_LUT_ENTRIES;
copy_from_kernel = 1;
fix_up = 1;
break;
case mdp_igc_rec601:
v17_usr_config.c0_c1_data = pp_igc_601;
v17_usr_config.c2_data = pp_igc_601;
v17_usr_config.len = IGC_LUT_ENTRIES;
copy_from_kernel = 1;
fix_up = 1;
break;
default:
pr_err("invalid format %d\n",
v17_usr_config.table_fmt);
ret = -EINVAL;
goto igc_config_exit;
}
v17_cache_data = pipe->pp_res.igc_cfg_payload;
if (!v17_cache_data)
v17_cache_data = kzalloc(sizeof(struct mdp_igc_lut_data_v1_7),
GFP_KERNEL);
if (!v17_cache_data) {
ret = -ENOMEM;
goto igc_config_exit;
} else {
pipe->pp_res.igc_cfg_payload = v17_cache_data;
pipe->pp_cfg.igc_cfg.cfg_payload = v17_cache_data;
}
v17_cache_data->c0_c1_data = pipe->pp_res.igc_c0_c1;
v17_cache_data->c2_data = pipe->pp_res.igc_c2;
v17_cache_data->len = IGC_LUT_ENTRIES;
if (copy_from_kernel) {
memcpy(v17_cache_data->c0_c1_data,
v17_usr_config.c0_c1_data,
IGC_LUT_ENTRIES * sizeof(u32));
memcpy(v17_cache_data->c2_data,
v17_usr_config.c2_data,
IGC_LUT_ENTRIES * sizeof(u32));
if (fix_up) {
for (i = 0; i < IGC_LUT_ENTRIES; i++)
v17_cache_data->c0_c1_data[i]
|= (v17_cache_data->c0_c1_data[i]
<< IGC_C1_SHIFT);
}
} else {
if (copy_from_user(v17_cache_data->c0_c1_data,
v17_usr_config.c0_c1_data,
IGC_LUT_ENTRIES * sizeof(u32))) {
pr_err("error in copying the c0_c1_data of size %zd\n",
IGC_LUT_ENTRIES * sizeof(u32));
ret = -EFAULT;
goto igc_config_exit;
}
if (copy_from_user(v17_cache_data->c2_data,
v17_usr_config.c2_data,
IGC_LUT_ENTRIES * sizeof(u32))) {
pr_err("error in copying the c2_data of size %zd\n",
IGC_LUT_ENTRIES * sizeof(u32));
ret = -EFAULT;
}
}
igc_config_exit:
if (ret || (config->ops & MDP_PP_OPS_DISABLE)) {
kfree(v17_cache_data);
pipe->pp_cfg.igc_cfg.cfg_payload = NULL;
pipe->pp_res.igc_cfg_payload = NULL;
}
return ret;
}
int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
struct mdp_pp_cache_res *res_cache,
u32 copy_from_kernel)
{
int ret = 0;
if (!config || !res_cache) {
pr_err("invalid param config %pK pp_res %pK\n",
config, res_cache);
return -EINVAL;
}
if (res_cache->block < SSPP_RGB || res_cache->block > DSPP) {
pr_err("invalid block for IGC %d\n", res_cache->block);
return -EINVAL;
}
if (!res_cache->mdss_pp_res && !res_cache->pipe_res) {
pr_err("NULL payload for block %d mdss_pp_res %pK pipe_res %pK\n",
res_cache->block, res_cache->mdss_pp_res,
res_cache->pipe_res);
ret = -EINVAL;
goto igc_exit;
}
switch (config->version) {
case mdp_igc_v1_7:
if (res_cache->block == DSPP) {
ret = pp_igc_lut_cache_params_v1_7(config,
res_cache->mdss_pp_res, copy_from_kernel);
if (ret)
pr_err("failed to cache IGC params for DSPP ret %d\n",
ret);
} else {
ret = pp_igc_lut_cache_params_pipe_v1_7(config,
res_cache->pipe_res, copy_from_kernel);
if (ret)
pr_err("failed to cache IGC params for SSPP ret %d\n",
ret);
}
break;
default:
pr_err("unsupported igc version %d\n",
config->version);
ret = -EINVAL;
break;
}
igc_exit:
return ret;
}
static int pp_pgc_lut_cache_params_v1_7(struct mdp_pgc_lut_data *config,
struct mdss_pp_res_type *mdss_pp_res,
int location)
{
int ret = 0;
u32 sz = 0;
u32 disp_num;
struct mdp_pgc_lut_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
struct mdss_pp_res_type_v1_7 *res_cache = NULL;
if (location != DSPP && location != LM) {
pr_err("Invalid location for pgc %d\n", location);
return -EINVAL;
}
disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
if (disp_num >= MDSS_BLOCK_DISP_NUM) {
pr_err("invalid disp_num %d\n", disp_num);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (!res_cache) {
pr_err("invalid resource payload\n");
return -EINVAL;
}
if (copy_from_user(&v17_usr_config, config->cfg_payload,
sizeof(v17_usr_config))) {
pr_err("failed to copy from user config info\n");
return -EFAULT;
}
if (v17_usr_config.len != PGC_LUT_ENTRIES) {
pr_err("invalid entries for pgc act %d exp %d\n",
v17_usr_config.len, PGC_LUT_ENTRIES);
return -EFAULT;
}
if (config->flags & MDP_PP_OPS_READ) {
pr_err("ops read not supported\n");
return -EINVAL;
}
if (!(config->flags & MDP_PP_OPS_WRITE)) {
pr_debug("ops write not set flags %d\n", config->flags);
if (location == DSPP)
mdss_pp_res->pgc_disp_cfg[disp_num].flags =
config->flags;
else
mdss_pp_res->argc_disp_cfg[disp_num].flags =
config->flags;
return 0;
}
if (location == DSPP) {
mdss_pp_res->pgc_disp_cfg[disp_num] = *config;
v17_cache_data = &res_cache->pgc_dspp_v17_data[disp_num];
v17_cache_data->c0_data = &res_cache->pgc_table_c0[disp_num][0];
v17_cache_data->c1_data = &res_cache->pgc_table_c1[disp_num][0];
v17_cache_data->c2_data = &res_cache->pgc_table_c2[disp_num][0];
mdss_pp_res->pgc_disp_cfg[disp_num].cfg_payload =
v17_cache_data;
} else {
mdss_pp_res->argc_disp_cfg[disp_num] = *config;
v17_cache_data = &res_cache->pgc_lm_v17_data[disp_num];
v17_cache_data->c0_data =
&res_cache->pgc_lm_table_c0[disp_num][0];
v17_cache_data->c1_data =
&res_cache->pgc_lm_table_c1[disp_num][0];
v17_cache_data->c2_data =
&res_cache->pgc_lm_table_c2[disp_num][0];
mdss_pp_res->argc_disp_cfg[disp_num].cfg_payload =
v17_cache_data;
}
v17_cache_data->len = 0;
sz = PGC_LUT_ENTRIES * sizeof(u32);
if (copy_from_user(v17_cache_data->c0_data, v17_usr_config.c0_data,
sz)) {
pr_err("failed to copy c0_data from user sz %d\n", sz);
ret = -EFAULT;
goto bail_out;
}
if (copy_from_user(v17_cache_data->c1_data, v17_usr_config.c1_data,
sz)) {
pr_err("failed to copy c1_data from user sz %d\n", sz);
ret = -EFAULT;
goto bail_out;
}
if (copy_from_user(v17_cache_data->c2_data, v17_usr_config.c2_data,
sz)) {
pr_err("failed to copy c2_data from user sz %d\n", sz);
ret = -EFAULT;
goto bail_out;
}
v17_cache_data->len = PGC_LUT_ENTRIES;
return 0;
bail_out:
if (location == DSPP)
mdss_pp_res->pgc_disp_cfg[disp_num].flags = 0;
else
mdss_pp_res->argc_disp_cfg[disp_num].flags = 0;
return ret;
}
int pp_pgc_lut_cache_params(struct mdp_pgc_lut_data *config,
struct mdss_pp_res_type *mdss_pp_res, int loc)
{
int ret = 0;
if (!config || !mdss_pp_res) {
pr_err("invalid param config %pK pp_res %pK\n",
config, mdss_pp_res);
return -EINVAL;
}
switch (config->version) {
case mdp_pgc_v1_7:
ret = pp_pgc_lut_cache_params_v1_7(config, mdss_pp_res, loc);
break;
default:
pr_err("unsupported igc version %d\n",
config->version);
ret = -EINVAL;
break;
}
return ret;
}
static int pp_pa_cache_params_v1_7(struct mdp_pa_v2_cfg_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
struct mdss_pp_res_type_v1_7 *res_cache;
struct mdp_pa_data_v1_7 *pa_cache_data, pa_usr_config;
int disp_num, ret = 0;
if (!config || !mdss_pp_res) {
pr_err("Invalid param config %pK pp_res %pK\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_v1_7) {
pr_err("Invalid pp_data_v1_7 %pK\n", mdss_pp_res->pp_data_v1_7);
return -EINVAL;
}
res_cache = mdss_pp_res->pp_data_v1_7;
if (config->flags & MDP_PP_OPS_READ) {
pr_err("Read op is not supported\n");
return -EINVAL;
}
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->pa_v2_disp_cfg[disp_num] = *config;
pa_cache_data = &res_cache->pa_v17_data[disp_num];
mdss_pp_res->pa_v2_disp_cfg[disp_num].cfg_payload =
(void *) pa_cache_data;
if (copy_from_user(&pa_usr_config, config->cfg_payload,
sizeof(pa_usr_config))) {
pr_err("Failed to copy v1_7 PA\n");
ret = -EFAULT;
goto pa_config_exit;
}
if ((config->flags & MDP_PP_OPS_DISABLE)) {
pr_debug("Disable PA\n");
ret = 0;
goto pa_config_exit;
}
if (!(config->flags & MDP_PP_OPS_WRITE)) {
pr_debug("op for PA %d\n", config->flags);
ret = 0;
goto pa_config_exit;
}
memcpy(pa_cache_data, &pa_usr_config, sizeof(pa_usr_config));
/* Copy six zone LUT if six zone is enabled to be written */
if (config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
if (pa_usr_config.six_zone_len != MDP_SIX_ZONE_LUT_SIZE) {
pr_err("Invalid six zone size, actual %d max %d\n",
pa_usr_config.six_zone_len,
MDP_SIX_ZONE_LUT_SIZE);
ret = -EINVAL;
goto pa_config_exit;
}
ret = copy_from_user(&res_cache->six_zone_lut_p0[disp_num][0],
pa_usr_config.six_zone_curve_p0,
pa_usr_config.six_zone_len * sizeof(u32));
if (ret) {
pr_err("copying six_zone_curve_p0 lut from userspace failed size %zd ret %d\n",
(sizeof(u32) * pa_usr_config.six_zone_len),
ret);
ret = -EFAULT;
goto pa_config_exit;
}
pa_cache_data->six_zone_curve_p0 =
&res_cache->six_zone_lut_p0[disp_num][0];
ret = copy_from_user(&res_cache->six_zone_lut_p1[disp_num][0],
pa_usr_config.six_zone_curve_p1,
pa_usr_config.six_zone_len * sizeof(u32));
if (ret) {
pr_err("copying six_zone_curve_p1 lut from userspace failed size %zd ret %d\n",
(sizeof(u32) * pa_usr_config.six_zone_len),
ret);
ret = -EFAULT;
goto pa_config_exit;
}
pa_cache_data->six_zone_curve_p1 =
&res_cache->six_zone_lut_p1[disp_num][0];
}
pa_config_exit:
if (ret || config->flags & MDP_PP_OPS_DISABLE) {
pa_cache_data->six_zone_len = 0;
pa_cache_data->six_zone_curve_p0 = NULL;
pa_cache_data->six_zone_curve_p1 = NULL;
}
return ret;
}
static int pp_pa_cache_params_pipe_v1_7(struct mdp_pa_v2_cfg_data *config,
struct mdss_mdp_pipe *pipe)
{
struct mdp_pa_data_v1_7 *pa_cache_data, pa_usr_config;
int ret = 0;
if (!config || !pipe) {
pr_err("Invalid param config %pK pipe %pK\n",
config, pipe);
return -EINVAL;
}
if (config->flags & MDP_PP_OPS_DISABLE) {
pr_debug("Disable PA on pipe %d\n", pipe->num);
goto pa_cache_pipe_exit;
}
if (config->flags & MDP_PP_OPS_READ) {
pr_err("Read op is not supported\n");
return -EINVAL;
}
if (!config->cfg_payload) {
pr_err("invalid PA config payload\n");
return -EINVAL;
}
if (copy_from_user(&pa_usr_config,
(void __user *) config->cfg_payload,
sizeof(pa_usr_config))) {
pr_err("failed to copy pa usr config\n");
return -EFAULT;
}
pa_cache_data = pipe->pp_res.pa_cfg_payload;
if (!pa_cache_data) {
pa_cache_data = kzalloc(sizeof(struct mdp_pa_data_v1_7),
GFP_KERNEL);
if (!pa_cache_data) {
ret = -ENOMEM;
goto pa_cache_pipe_exit;
} else
pipe->pp_res.pa_cfg_payload = pa_cache_data;
}
*pa_cache_data = pa_usr_config;
/* No six zone in SSPP */
pa_cache_data->six_zone_len = 0;
pa_cache_data->six_zone_curve_p0 = NULL;
pa_cache_data->six_zone_curve_p1 = NULL;
pa_cache_pipe_exit:
if (ret || (config->flags & MDP_PP_OPS_DISABLE)) {
kfree(pipe->pp_res.pa_cfg_payload);
pipe->pp_res.pa_cfg_payload = NULL;
}
pipe->pp_cfg.pa_v2_cfg_data.cfg_payload = pipe->pp_res.pa_cfg_payload;
return ret;
}
int pp_pa_cache_params(struct mdp_pa_v2_cfg_data *config,
struct mdp_pp_cache_res *res_cache)
{
int ret = 0;
if (!config || !res_cache) {
pr_err("invalid param config %pK pp_res %pK\n",
config, res_cache);
return -EINVAL;
}
if (res_cache->block != SSPP_VIG && res_cache->block != DSPP) {
pr_err("invalid block for PA %d\n", res_cache->block);
return -EINVAL;
}
if (!res_cache->mdss_pp_res && !res_cache->pipe_res) {
pr_err("NULL payload for block %d mdss_pp_res %pK pipe_res %pK\n",
res_cache->block, res_cache->mdss_pp_res,
res_cache->pipe_res);
return -EINVAL;
}
switch (config->version) {
case mdp_pa_v1_7:
if (res_cache->block == DSPP) {
ret = pp_pa_cache_params_v1_7(config,
res_cache->mdss_pp_res);
if (ret)
pr_err("failed to cache PA params for DSPP ret %d\n",
ret);
} else {
ret = pp_pa_cache_params_pipe_v1_7(config,
res_cache->pipe_res);
if (ret)
pr_err("failed to cache PA params for SSPP ret %d\n",
ret);
}
break;
default:
pr_err("unsupported pa version %d\n",
config->version);
ret = -EINVAL;
break;
}
return ret;
}
int pp_copy_layer_igc_payload(struct mdp_overlay_pp_params *pp_info)
{
void *cfg_payload = NULL;
int ret = 0;
switch (pp_info->igc_cfg.version) {
case mdp_igc_v1_7:
cfg_payload = kmalloc(
sizeof(struct mdp_igc_lut_data_v1_7),
GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
ret = copy_from_user(cfg_payload,
pp_info->igc_cfg.cfg_payload,
sizeof(struct mdp_igc_lut_data_v1_7));
if (ret) {
pr_err("layer list copy from user failed, IGC cfg payload = %pK\n",
pp_info->igc_cfg.cfg_payload);
ret = -EFAULT;
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("No version set, fallback to legacy IGC version\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->igc_cfg.cfg_payload = cfg_payload;
return ret;
}
int pp_copy_layer_hist_lut_payload(struct mdp_overlay_pp_params *pp_info)
{
void *cfg_payload = NULL;
int ret = 0;
switch (pp_info->hist_lut_cfg.version) {
case mdp_hist_lut_v1_7:
cfg_payload = kmalloc(
sizeof(struct mdp_hist_lut_data_v1_7),
GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
ret = copy_from_user(cfg_payload,
pp_info->hist_lut_cfg.cfg_payload,
sizeof(struct mdp_hist_lut_data_v1_7));
if (ret) {
pr_err("layer list copy from user failed, Hist LUT cfg payload = %pK\n",
pp_info->hist_lut_cfg.cfg_payload);
ret = -EFAULT;
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("No version set, fallback to legacy Hist LUT version\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->hist_lut_cfg.cfg_payload = cfg_payload;
return ret;
}
int pp_copy_layer_pa_payload(struct mdp_overlay_pp_params *pp_info)
{
void *cfg_payload = NULL;
int ret = 0;
switch (pp_info->pa_v2_cfg_data.version) {
case mdp_pa_v1_7:
cfg_payload = kmalloc(
sizeof(struct mdp_pa_data_v1_7),
GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
ret = copy_from_user(cfg_payload,
pp_info->pa_v2_cfg_data.cfg_payload,
sizeof(struct mdp_pa_data_v1_7));
if (ret) {
pr_err("layer list copy from user failed, PA cfg payload = %pK\n",
pp_info->pa_v2_cfg_data.cfg_payload);
ret = -EFAULT;
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("No version set, fallback to legacy PA version\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->pa_v2_cfg_data.cfg_payload = cfg_payload;
return ret;
}
int pp_copy_layer_pcc_payload(struct mdp_overlay_pp_params *pp_info)
{
void *cfg_payload = NULL;
int ret = 0;
switch (pp_info->pcc_cfg_data.version) {
case mdp_pcc_v1_7:
cfg_payload = kmalloc(
sizeof(struct mdp_pcc_data_v1_7),
GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
ret = copy_from_user(cfg_payload,
pp_info->pcc_cfg_data.cfg_payload,
sizeof(struct mdp_pcc_data_v1_7));
if (ret) {
pr_err("layer list copy from user failed, PCC cfg payload = %pK\n",
pp_info->pcc_cfg_data.cfg_payload);
ret = -EFAULT;
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("No version set, fallback to legacy PCC version\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->pcc_cfg_data.cfg_payload = cfg_payload;
return ret;
}