// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2014-2018, 2020, The Linux Foundation. All rights reserved.
 *
 */

#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_igc_lut_cache_params_v3(struct mdp_igc_lut_data *config,
			    struct mdss_pp_res_type *mdss_pp_res,
			    u32 copy_from_kernel);

static int pp_igc_lut_cache_params_pipe_v3(struct mdp_igc_lut_data *config,
			    struct mdss_mdp_pipe *pipe,
			    u32 copy_from_kernel);


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 usr 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;
	case mdp_igc_v3:
		if (res_cache->block == DSPP) {
			ret = pp_igc_lut_cache_params_v3(config,
				res_cache->mdss_pp_res, copy_from_kernel);
			if (ret)
				pr_err("cache DSPP IGC params fail ret %d version %d\n",
					ret, config->version);
		} else {
			ret = pp_igc_lut_cache_params_pipe_v3(config,
				res_cache->pipe_res, copy_from_kernel);
			if (ret)
				pr_err("cache SSPP IGC params fail ret %d version %d\n",
					ret, config->version);
		}
		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;
	size_t sz = 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));
		break;
	case mdp_igc_v3:
		cfg_payload = kmalloc(
				sizeof(struct mdp_igc_lut_data_payload),
				GFP_KERNEL);
		if (!cfg_payload) {
			ret = -ENOMEM;
			goto exit;
		}
		sz = offsetof(struct mdp_igc_lut_data_payload, strength) +
			sizeof(u32);
		ret = copy_from_user(cfg_payload,
				pp_info->igc_cfg.cfg_payload, sz);
		break;
	default:
		pr_debug("No version set, fallback to legacy IGC version\n");
		cfg_payload = NULL;
		break;
	}
exit:
	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;
	}
	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;
}

static int pp_pa_dither_cache_params_v1_7(
			struct mdp_dither_cfg_data *config,
			struct mdss_pp_res_type *mdss_pp_res)
{
	struct mdss_pp_res_type_v1_7 *res_cache;
	int disp_num, ret = 0;
	size_t sz = 0;
	struct mdp_pa_dither_res_data_v1_7 *res_data;
	struct mdp_pa_dither_data dither_data;

	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 || !mdss_pp_res->pp_data_v1_7) {
		pr_err("invalid param mdss_pp_res %pK pp_data_res %pK\n",
			mdss_pp_res,
			((mdss_pp_res) ? mdss_pp_res->pp_data_v1_7 : NULL));
		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;
	res_data = &res_cache->pa_dither_data[disp_num];
	if ((config->flags & MDP_PP_OPS_DISABLE) ||
		!(config->flags & MDP_PP_OPS_WRITE)) {
		mdss_pp_res->pa_dither_cfg[disp_num] = *config;
		mdss_pp_res->pa_dither_cfg[disp_num].cfg_payload =
			(void *) res_data;
		return 0;
	}
	sz = offsetof(struct mdp_pa_dither_data, offset_en)
		+ sizeof(dither_data.offset_en);
	memset(&dither_data, 0, sizeof(dither_data));
	ret = copy_from_user(&dither_data, config->cfg_payload, sz);
	if (ret) {
		pr_err("failed to copy the dither data ret %d sz %zd\n",
			 ret, sz);
		ret = -EFAULT;
		goto exit;
	}
	if (dither_data.matrix_sz != MDP_DITHER_DATA_V1_7_SZ) {
		pr_err("invalid matrix len %d expected %d\n",
			dither_data.matrix_sz, MDP_DITHER_DATA_V1_7_SZ);
		ret = -EINVAL;
		goto exit;
	}
	res_data->offset_en = dither_data.offset_en;
	res_data->strength = dither_data.strength;
	res_data->matrix_sz = MDP_DITHER_DATA_V1_7_SZ;
	ret = copy_from_user(res_data->matrix_data,
			     (u8 *)((unsigned long)dither_data.matrix_data),
			     (MDP_DITHER_DATA_V1_7_SZ * sizeof(u32)));
	if (ret) {
		pr_err("failed to copy the dither matrix ret %d sz %z\n", ret,
			MDP_DITHER_DATA_V1_7_SZ * sizeof(u32));
		ret = -EFAULT;
		goto exit;
	}
	mdss_pp_res->pa_dither_cfg[disp_num] = *config;
	mdss_pp_res->pa_dither_cfg[disp_num].cfg_payload =
		(void *) res_data;
exit:
	return ret;
}

int pp_pa_dither_cache_params(struct mdp_dither_cfg_data *config,
			 struct mdp_pp_cache_res *res_cache)
{
	int ret = 0;

	if (!config || !res_cache) {
		pr_err("invalid params config %pK res_cache %pK\n",
			config, res_cache);
		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_dither_pa_v1_7:
		if (res_cache->block == DSPP)
			ret = pp_pa_dither_cache_params_v1_7(config,
					res_cache->mdss_pp_res);
		else
			ret = -ENOTSUPP;
		break;
	default:
		ret = -EINVAL;
		break;
	}
	return ret;
}

static int pp_igc_lut_cache_params_v3(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_v3 *res_cache;
	struct mdp_igc_lut_data_payload v3_usr_config;
	struct mdp_igc_lut_data_config *v3_cache_data, *v3_kernel_data = NULL;
	u32 disp_num, len = 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_v3) {
		pr_err("invalid pp_data_v3 %pK\n", mdss_pp_res->pp_data_v3);
		return -EINVAL;
	}
	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;
	if (!(config->ops & MDP_PP_OPS_WRITE)) {
		pr_debug("op for igc %d\n", config->ops);
		mdss_pp_res->igc_disp_cfg[disp_num] = *config;
		goto igc_config_exit;
	}
	res_cache = mdss_pp_res->pp_data_v3;
	v3_cache_data = &res_cache->igc_v3_data[disp_num];
	if (!v3_cache_data->c0_c1_data || !v3_cache_data->c2_data) {
		pr_err("invalid payload c0_c1_data %pK c2_data %pK\n",
			v3_cache_data->c0_c1_data, v3_cache_data->c2_data);
		goto igc_config_exit;
	}
	if (!copy_from_kernel) {
		if (copy_from_user(&v3_usr_config,
				   config->cfg_payload,
				   sizeof(v3_usr_config))) {
			pr_err("failed to copy igc config\n");
			ret = -EFAULT;
			goto igc_config_exit;
		}
		len = v3_usr_config.len;
	} else {
		if (!config->cfg_payload) {
			pr_err("can't copy config info NULL payload\n");
			ret = -EINVAL;
			goto igc_config_exit;
		}
		v3_kernel_data = config->cfg_payload;
		len = v3_kernel_data->len;
	}
	if (copy_from_kernel && (!v3_kernel_data->c0_c1_data ||
	    !v3_kernel_data->c2_data)) {
		pr_err("copy from kernel invalid params c0_c1_data %pK c2_data %pK\n",
			v3_kernel_data->c0_c1_data,
			v3_kernel_data->c2_data);
		ret = -EINVAL;
		goto igc_config_exit;
	}
	if (len != IGC_LUT_ENTRIES) {
		pr_err("Invalid table size %d exp %d\n",
			len, IGC_LUT_ENTRIES);
		ret = -EINVAL;
		goto igc_config_exit;
	}
	if (copy_from_kernel) {
		memcpy(v3_cache_data->c0_c1_data,
		       v3_kernel_data->c0_c1_data,
		       len * sizeof(u32));
		memcpy(v3_cache_data->c2_data, v3_kernel_data->c2_data,
		       len * sizeof(u32));
		v3_cache_data->len = len;
		v3_cache_data->strength = v3_kernel_data->strength;
		v3_cache_data->table_fmt = v3_kernel_data->table_fmt;
	} else {
		ret = copy_from_user(v3_cache_data->c0_c1_data,
			     (u8 *)((unsigned long)v3_usr_config.c0_c1_data),
			     len * sizeof(u32));
		if (ret) {
			pr_err("copy from user failed for c0_c1_data size %zd ret %d\n",
				len * sizeof(u32), ret);
			ret = -EFAULT;
			goto igc_config_exit;
		}
		ret = copy_from_user(v3_cache_data->c2_data,
			     (u8 *)((unsigned long)v3_usr_config.c2_data),
			     len * sizeof(u32));
		if (ret) {
			pr_err("copy from user failed for c2_data size %zd ret %d\n",
			       len * sizeof(u32), ret);
			ret = -EFAULT;
			goto igc_config_exit;
		}
		v3_cache_data->len = len;
		v3_cache_data->strength = v3_usr_config.strength;
		v3_cache_data->table_fmt = v3_usr_config.table_fmt;
	}
	mdss_pp_res->igc_disp_cfg[disp_num] = *config;
	mdss_pp_res->igc_disp_cfg[disp_num].cfg_payload =
				(void *)v3_cache_data;
igc_config_exit:
	return ret;
}

static int pp_igc_lut_cache_params_pipe_v3(
		struct mdp_igc_lut_data *config, struct mdss_mdp_pipe *pipe,
		u32 copy_from_kernel)
{
	struct mdp_igc_lut_data_config *v3_cache_data = NULL;
	struct mdp_igc_lut_data_payload v3_usr_config;
	u32 *c0_c1_data, *c2_data, len;
	int ret = 0, fix_up = 0, i = 0;
	u32 table_fmt = mdp_igc_rec_max, strength = 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->ops & MDP_PP_OPS_WRITE)) {
		pr_debug("op for gamut %d\n", config->ops);
		goto igc_config_exit;
	}

	if (!config->cfg_payload) {
		pr_err("can't copy config info NULL payload\n");
		ret = -EINVAL;
		goto igc_config_exit;
	}

	v3_cache_data = pipe->pp_res.igc_cfg_payload;
	if (!v3_cache_data)
		v3_cache_data = kzalloc(sizeof(*v3_cache_data), GFP_KERNEL);
	if (!v3_cache_data) {
		ret = -ENOMEM;
		goto igc_config_exit;
	} else {
		pipe->pp_res.igc_cfg_payload = v3_cache_data;
		pipe->pp_cfg.igc_cfg.cfg_payload = v3_cache_data;
	}

	if (copy_from_kernel) {
		memcpy(v3_cache_data, config->cfg_payload,
			sizeof(*v3_cache_data));
		table_fmt = v3_cache_data->table_fmt;
		len = v3_cache_data->len;
		strength = 0;
	} else {
		memcpy(&v3_usr_config, config->cfg_payload,
			sizeof(v3_usr_config));
		table_fmt = v3_usr_config.table_fmt;
		len = v3_usr_config.len;
		strength = v3_usr_config.strength;
	}
	switch (table_fmt) {
	case mdp_igc_custom:
		if (len != IGC_LUT_ENTRIES) {
			pr_err("invalid igc len %d exp %d\n", len,
				IGC_LUT_ENTRIES);
			ret = -EINVAL;
			goto igc_config_exit;
		}
		if (!copy_from_kernel)
			break;
		c0_c1_data = v3_cache_data->c0_c1_data;
		c2_data = v3_cache_data->c2_data;
		if (!c0_c1_data || !c2_data) {
			pr_err("invalid param c0_c1_data %pK c2_data %pK\n",
				c0_c1_data, c2_data);
			ret = -EINVAL;
			goto igc_config_exit;
		}
		break;
	case mdp_igc_rec709:
		c0_c1_data = pp_igc_709;
		c2_data = pp_igc_709;
		v3_usr_config.len = IGC_LUT_ENTRIES;
		copy_from_kernel = 1;
		fix_up = 1;
		break;
	case mdp_igc_srgb:
		c0_c1_data = pp_igc_srgb;
		c2_data = pp_igc_srgb;
		v3_usr_config.len = IGC_LUT_ENTRIES;
		copy_from_kernel = 1;
		fix_up = 1;
		break;
	case mdp_igc_rec601:
		c0_c1_data = pp_igc_601;
		c2_data = pp_igc_601;
		v3_usr_config.len = IGC_LUT_ENTRIES;
		copy_from_kernel = 1;
		fix_up = 1;
		break;
	default:
		pr_err("invalid format %d\n", table_fmt);
		ret = -EINVAL;
		goto igc_config_exit;
	}
	v3_cache_data->c0_c1_data = pipe->pp_res.igc_c0_c1;
	v3_cache_data->c2_data = pipe->pp_res.igc_c2;
	v3_cache_data->len = IGC_LUT_ENTRIES;
	v3_cache_data->strength = strength;
	v3_cache_data->table_fmt = table_fmt;
	if (copy_from_kernel) {
		memcpy(v3_cache_data->c0_c1_data, c0_c1_data,
				IGC_LUT_ENTRIES * sizeof(u32));
		memcpy(v3_cache_data->c2_data, c2_data,
				IGC_LUT_ENTRIES * sizeof(u32));
		if (fix_up) {
			for (i = 0; i < IGC_LUT_ENTRIES; i++)
				v3_cache_data->c0_c1_data[i]
					|= (v3_cache_data->c0_c1_data[i]
							<< IGC_C1_SHIFT);
		}
	} else {
		if (copy_from_user(v3_cache_data->c0_c1_data,
				(u8 *)((unsigned long)v3_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(v3_cache_data->c2_data,
				(u8 *)((unsigned long)v3_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(v3_cache_data);
		pipe->pp_cfg.igc_cfg.cfg_payload = NULL;
		pipe->pp_res.igc_cfg_payload = NULL;
	}
	return ret;
}

