Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db59dc7a authored by Ping Li's avatar Ping Li Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: Update histogram and PA LUT in mdss V3



Histogram and PA LUT register addresses have been updated in msmcobalt,
this change updates the corresponding histogram and PA LUT offsets for
mdss V3.

CRs-Fixed: 985286
Change-Id: Icdb01e9fb222614cb60ae7951b68018230e4a448
Signed-off-by: default avatarPing Li <pingli@codeaurora.org>
parent 0b20839e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -616,6 +616,7 @@ struct pp_sts_type {
	u32 gamut_sts;
	u32 pgc_sts;
	u32 sharp_sts;
	u32 hist_sts;
	u32 side_sts;
};

+46 −18
Original line number Diff line number Diff line
@@ -407,7 +407,8 @@ static struct mdss_pp_res_type *mdss_pp_res;

static u32 pp_hist_read(char __iomem *v_addr,
				struct pp_hist_col_info *hist_info);
static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix,
				struct pp_sts_type *pp_sts);
static int pp_hist_disable(struct pp_hist_col_info *hist_info);
static void pp_update_pcc_regs(char __iomem *addr,
				struct mdp_pcc_cfg_data *cfg_ptr);
@@ -1048,7 +1049,8 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
	}

	/* Histogram collection enabled checked inside pp_hist_setup */
	pp_hist_setup(op, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer_left);
	pp_hist_setup(op, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer_left,
			&pipe->pp_res.pp_sts);

	if (!(pipe->flags & MDP_OVERLAY_PP_CFG_EN)) {
		pr_debug("Overlay PP CFG enable not set\n");
@@ -2002,11 +2004,12 @@ static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num)
}

/* Assumes that function will be called from within clock enabled space*/
static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix)
static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix,
			struct pp_sts_type *pp_sts)
{
	int ret = -EINVAL;
	int ret = 0;
	char __iomem *base;
	u32 op_flags;
	u32 op_flags = 0, block_type = 0;
	struct mdss_mdp_pipe *pipe;
	struct pp_hist_col_info *hist_info;
	unsigned long flag;
@@ -2019,6 +2022,7 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix)
	intr_mask = 1;
	if (mix && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG)) {
		/* HIST_EN */
		block_type = DSPP;
		op_flags = BIT(16);
		hist_info = &mdss_pp_res->dspp_hist[mix->num];
		base = mdss_mdp_get_dspp_addr_off(PP_BLOCK(block));
@@ -2029,6 +2033,7 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix)
	} else if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG &&
		(pp_driver_ops.is_sspp_hist_supp) &&
		(pp_driver_ops.is_sspp_hist_supp())) {
		block_type = SSPP_VIG;
		pipe = __get_hist_pipe(PP_BLOCK(block));
		if (IS_ERR_OR_NULL(pipe)) {
			pr_debug("pipe DNE (%d)\n",
@@ -2041,18 +2046,38 @@ static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix)
		base = pipe->base;
		mdss_mdp_pipe_unmap(pipe);
	} else {
		ret = -EINVAL;
		goto error;
	}

	mutex_lock(&hist_info->hist_mutex);
	spin_lock_irqsave(&hist_info->hist_lock, flag);
	if (hist_info->col_en) {
	/*
	 * Set histogram interrupt if histogram collection is enabled. The
	 * interrupt register offsets are the same across different mdss
	 * versions so far, hence mdss_mdp_hist_irq_set_mask is used for
	 * all the mdss versions.
	 */
	if (hist_info->col_en)
		mdss_mdp_hist_irq_set_mask(intr_mask << hist_info->intr_shift);
	/*
	 * Starting from msmcobalt, the histogram enable bit has been moved
	 * from DSPP opmode register to PA_HIST opmode register, hence we need
	 * to update the histogram enable bit differently based on mdss version.
	 * If HIST pp_set_config is defined, we will enable or disable the
	 * hist_en bit in PA_HIST opmode register inside HIST pp_set_config
	 * function; else, we only need to add the hist_en bit to the *op when
	 * histogram collection is enable, and *op will be passed to
	 * pp_dspp_setup to update the DSPP opmode register.
	 */
	if (pp_ops[HIST].pp_set_config)
		ret = pp_ops[HIST].pp_set_config(base, pp_sts, hist_info,
							block_type);
	else if (hist_info->col_en)
		*op |= op_flags;
	}

	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
	mutex_unlock(&hist_info->hist_mutex);
	ret = 0;
error:
	return ret;
}
@@ -2195,14 +2220,20 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
			(pp_driver_ops.gamut_clk_gate_en))
		pp_driver_ops.gamut_clk_gate_en(base +
					mdata->pp_block_off.dspp_gamut_off);
	ret = pp_hist_setup(&opmode, MDSS_PP_DSPP_CFG | dspp_num, mixer);

	if (disp_num < MDSS_BLOCK_DISP_NUM) {
		pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
		pp_sts->side_sts = side;

		ret = pp_hist_setup(&opmode, MDSS_PP_DSPP_CFG | dspp_num, mixer,
				pp_sts);
		if (ret)
			goto dspp_exit;

	if (disp_num < MDSS_BLOCK_DISP_NUM)
		flags = mdss_pp_res->pp_disp_flags[disp_num];
	else
	} else {
		flags = 0;
	}

	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
	if (dspp_num < mdata->nad_cfgs && disp_num < mdata->nad_cfgs &&
@@ -2218,9 +2249,6 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
	if ((!flags) && (!(opmode)) && (!ad_flags))
		goto dspp_exit;

	pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
	pp_sts->side_sts = side;

	if (flags & PP_FLAGS_DIRTY_PA) {
		if (!pp_ops[PA].pp_set_config) {
			if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
@@ -2847,7 +2875,7 @@ int mdss_mdp_pp_init(struct device *dev)
				vig[i].pp_res.hist.intr_shift = 10;
			if (pp_driver_ops.get_hist_offset) {
				ret = pp_driver_ops.get_hist_offset(
					DSPP, &ctl_off);
					SSPP_VIG, &ctl_off);
				if (ret) {
					pr_err("get_hist_offset ret %d\n",
						ret);
@@ -4803,7 +4831,7 @@ hist_stop_clk:
}

/**
 * mdss_mdp_hist_intr_req() - Request changes the histogram interupts
 * mdss_mdp_hist_intr_req() - Request changes the histogram interrupts
 * @intr: structure containting state of interrupt register
 * @bits: the bits on interrupt register that should be changed
 * @en: true if bits should be set, false if bits should be cleared
+3 −2
Original line number Diff line number Diff line
@@ -421,7 +421,7 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
		hist_addr += 4;
	}
	if (copy_to_user(lut_data->data, data, sz)) {
		pr_err("faild to copy the hist_lut back to user\n");
		pr_err("failed to copy the hist_lut back to user\n");
		ret = -EFAULT;
	}
	kfree(data);
@@ -503,7 +503,8 @@ static int pp_hist_lut_set_config(char __iomem *base_addr,
	}
	if (lut_cfg_data->hist_lut_first)
		pp_sts->enhist_sts |= PP_STS_PA_LUT_FIRST;

	else
		pp_sts->enhist_sts &= ~PP_STS_PA_LUT_FIRST;

	writel_relaxed(1, swap_addr);

+304 −2
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
#include "mdss_mdp_pp_common.h"

#define IGC_DSPP_OP_MODE_EN BIT(0)

#define ENHIST_BIT_SHIFT 16
/* PA related define */

/* Offsets from DSPP/VIG base to PA block */
@@ -56,6 +56,24 @@
#define PA_LUTV_REG_OFF 0x200
#define PA_HIST_RAM_REG_OFF 0x400

/* histogram prototypes */
static int pp_get_hist_offset(u32 block, u32 *ctl_off);
static int pp_hist_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data,
		u32 block_type);
static int pp_hist_get_config(char __iomem *base_addr, void *cfg_data,
		u32 block_type, u32 disp_num);

/* PA LUT prototypes */
static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
			   u32 block_type, u32 disp_num);
static int pp_hist_lut_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data,
		u32 block_type);
static int pp_hist_lut_get_version(u32 *version);
static void pp_hist_lut_opmode_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts);

static int pp_pa_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data,
		u32 block_type);
@@ -103,6 +121,16 @@ void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops)
	ops->pp_ops[PA].pp_get_config = pp_pa_get_config;
	ops->pp_ops[PA].pp_get_version = pp_pa_get_version;

	/* HIST_LUT ops */
	ops->pp_ops[HIST_LUT].pp_set_config = pp_hist_lut_set_config;
	ops->pp_ops[HIST_LUT].pp_get_config = pp_hist_lut_get_config;
	ops->pp_ops[HIST_LUT].pp_get_version = pp_hist_lut_get_version;

	/* HIST ops */
	ops->pp_ops[HIST].pp_set_config = pp_hist_set_config;
	ops->pp_ops[HIST].pp_get_config = pp_hist_get_config;
	ops->pp_ops[HIST].pp_get_version = NULL;

	/* Dither ops */
	ops->pp_ops[DITHER].pp_set_config = pp_dither_set_config;
	ops->pp_ops[DITHER].pp_get_config = pp_dither_get_config;
@@ -111,10 +139,278 @@ void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops)
	/* Set opmode pointers */
	ops->pp_opmode_config = pp_opmode_config;

	ops->get_hist_offset = pp_get_hist_offset;
	ops->gamut_clk_gate_en = NULL;

	return pp_cfg;
}

static int pp_get_hist_offset(u32 block, u32 *ctl_off)
{
	int ret = 0;

	if (!ctl_off) {
		pr_err("invalid params ctl_off %p\n", ctl_off);
		return -EINVAL;
	}

	switch (block) {
	case SSPP_VIG:
		*ctl_off = PA_VIG_BLOCK_REG_OFF + PA_HIST_REG_OFF;
		break;
	case DSPP:
		*ctl_off = PA_DSPP_BLOCK_REG_OFF + PA_HIST_REG_OFF;
		break;
	default:
		pr_err("Invalid block type %d\n", block);
		ret = -EINVAL;
		break;
	}
	return ret;
}

static int pp_hist_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data, u32 block_type)
{
	u32 opmode = 0;
	struct pp_hist_col_info *hist_info = NULL;

	if (!base_addr || !cfg_data || !pp_sts) {
		pr_err("invalid params base_addr %p cfg_data %p pp_sts_type %p\n",
		      base_addr, cfg_data, pp_sts);
		return -EINVAL;
	}

	if (block_type != DSPP) {
		pr_err("Invalid block type %d\n", block_type);
		return -EINVAL;
	}

	hist_info = (struct pp_hist_col_info *)cfg_data;
	opmode = readl_relaxed(base_addr + PA_DSPP_BLOCK_REG_OFF +
				PA_OP_MODE_REG_OFF);
	/* set the hist_en bit */
	if (hist_info->col_en) {
		pp_sts->hist_sts |= PP_STS_ENABLE;
		opmode |= BIT(16);
	} else {
		pp_sts->hist_sts &= ~PP_STS_ENABLE;
		opmode &= ~BIT(16);
	}

	writel_relaxed(opmode, base_addr + PA_DSPP_BLOCK_REG_OFF +
			PA_OP_MODE_REG_OFF);
	return 0;
}

static int pp_hist_get_config(char __iomem *base_addr, void *cfg_data,
			   u32 block_type, u32 disp_num)
{
	int i = 0;
	u32 sum = 0;
	struct pp_hist_col_info *hist_info = NULL;
	char __iomem *hist_addr;

	if (!base_addr || !cfg_data) {
		pr_err("invalid params base_addr %p cfg_data %p\n",
		       base_addr, cfg_data);
		return -EINVAL;
	}

	if (block_type != DSPP) {
		pr_err("Invalid block type %d\n", block_type);
		return -EINVAL;
	}

	hist_info = (struct pp_hist_col_info *) cfg_data;
	hist_addr = base_addr + PA_DSPP_BLOCK_REG_OFF + PA_HIST_RAM_REG_OFF;

	for (i = 0; i < HIST_V_SIZE; i++) {
		hist_info->data[i] = readl_relaxed(hist_addr) & REG_MASK(24);
		hist_addr += 0x4;
		sum += hist_info->data[i];
	}
	hist_info->hist_cnt_read++;
	return sum;
}

static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
			   u32 block_type, u32 disp_num)
{

	int ret = 0, i = 0;
	char __iomem *hist_lut_addr;
	u32 sz = 0, temp = 0, *data = NULL;
	struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
	struct mdp_hist_lut_data *lut_cfg_data = NULL;

	if (!base_addr || !cfg_data) {
		pr_err("invalid params base_addr %p cfg_data %p\n",
		       base_addr, cfg_data);
		return -EINVAL;
	}

	if (block_type != DSPP) {
		pr_err("Invalid block type %d\n", block_type);
		return -EINVAL;
	}

	lut_cfg_data = (struct mdp_hist_lut_data *) cfg_data;
	if (!(lut_cfg_data->ops & MDP_PP_OPS_READ)) {
		pr_err("read ops not set for hist_lut %d\n", lut_cfg_data->ops);
		return 0;
	}
	if (lut_cfg_data->version != mdp_hist_lut_v1_7 ||
		!lut_cfg_data->cfg_payload) {
		pr_err("invalid hist_lut version %d payload %p\n",
		       lut_cfg_data->version, lut_cfg_data->cfg_payload);
		return -EINVAL;
	}
	lut_data = lut_cfg_data->cfg_payload;
	if (lut_data->len != ENHIST_LUT_ENTRIES) {
		pr_err("invalid hist_lut len %d", lut_data->len);
		return -EINVAL;
	}
	sz = ENHIST_LUT_ENTRIES * sizeof(u32);
	if (!access_ok(VERIFY_WRITE, lut_data->data, sz)) {
		pr_err("invalid lut address for hist_lut sz %d\n", sz);
		return -EFAULT;
	}

	hist_lut_addr = base_addr + PA_DSPP_BLOCK_REG_OFF + PA_LUTV_REG_OFF;

	data = kzalloc(sz, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	for (i = 0; i < ENHIST_LUT_ENTRIES; i += 2) {
		temp = readl_relaxed(hist_lut_addr);
		data[i] = temp & REG_MASK(10);
		data[i + 1] =
			(temp & REG_MASK_SHIFT(10, 16)) >> ENHIST_BIT_SHIFT;
		hist_lut_addr += 4;
	}
	if (copy_to_user(lut_data->data, data, sz)) {
		pr_err("failed to copy the hist_lut back to user\n");
		ret = -EFAULT;
	}
	kfree(data);
	return ret;
}

static int pp_hist_lut_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data,
		u32 block_type)
{
	int ret = 0, i = 0;
	u32 temp = 0;
	struct mdp_hist_lut_data *lut_cfg_data = NULL;
	struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
	char __iomem *hist_lut_addr = NULL, *swap_addr = NULL;

	if (!base_addr || !cfg_data || !pp_sts) {
		pr_err("invalid params base_addr %p cfg_data %p pp_sts_type %p\n",
		      base_addr, cfg_data, pp_sts);
		return -EINVAL;
	}

	if (block_type != DSPP) {
		pr_err("Invalid block type %d\n", block_type);
		return -EINVAL;
	}

	lut_cfg_data = (struct mdp_hist_lut_data *) cfg_data;
	if (lut_cfg_data->version != mdp_hist_lut_v1_7) {
		pr_err("invalid hist_lut version %d\n", lut_cfg_data->version);
		return -EINVAL;
	}

	if (!(lut_cfg_data->ops & ~(MDP_PP_OPS_READ))) {
		pr_err("only read ops set for lut\n");
		return ret;
	}
	if (lut_cfg_data->ops & MDP_PP_OPS_DISABLE ||
		!(lut_cfg_data->ops & MDP_PP_OPS_WRITE)) {
		pr_debug("non write ops set %d\n", lut_cfg_data->ops);
		goto hist_lut_set_sts;
	}
	lut_data = lut_cfg_data->cfg_payload;
	if (!lut_data) {
		pr_err("invalid hist_lut cfg_payload %p\n", lut_data);
		return -EINVAL;
	}

	if (lut_data->len != ENHIST_LUT_ENTRIES || !lut_data->data) {
		pr_err("invalid hist_lut len %d data %p\n",
		       lut_data->len, lut_data->data);
		return -EINVAL;
	}

	hist_lut_addr = base_addr + PA_DSPP_BLOCK_REG_OFF + PA_LUTV_REG_OFF;
	swap_addr = base_addr + PA_DSPP_BLOCK_REG_OFF + PA_LUTV_SWAP_REG_OFF;

	for (i = 0; i < ENHIST_LUT_ENTRIES; i += 2) {
		temp = (lut_data->data[i] & REG_MASK(10)) |
			((lut_data->data[i + 1] & REG_MASK(10))
			 << ENHIST_BIT_SHIFT);

		writel_relaxed(temp, hist_lut_addr);
		hist_lut_addr += 4;
	}

	writel_relaxed(1, swap_addr);

hist_lut_set_sts:
	if (lut_cfg_data->ops & MDP_PP_OPS_DISABLE) {
		pp_sts->enhist_sts &= ~(PP_STS_ENABLE | PP_STS_PA_LUT_FIRST);
	} else if (lut_cfg_data->ops & MDP_PP_OPS_ENABLE) {
		pp_sts->enhist_sts |= PP_STS_ENABLE;
		if (lut_cfg_data->hist_lut_first)
			pp_sts->enhist_sts |= PP_STS_PA_LUT_FIRST;
		else
			pp_sts->enhist_sts &= ~PP_STS_PA_LUT_FIRST;
	}

	pp_hist_lut_opmode_config(base_addr + PA_DSPP_BLOCK_REG_OFF, pp_sts);
	return ret;
}

static int pp_hist_lut_get_version(u32 *version)
{
	if (!version) {
		pr_err("invalid param version %p\n", version);
		return -EINVAL;
	}
	*version = mdp_hist_lut_v1_7;
	return 0;
}

static void pp_hist_lut_opmode_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts)
{
	u32 opmode = 0;

	if (!base_addr || !pp_sts) {
		pr_err("invalid params base_addr %p pp_sts_type %p\n",
			base_addr, pp_sts);
		return;
	}
	opmode = readl_relaxed(base_addr + PA_OP_MODE_REG_OFF);

	/* set the hist_lutv_en and hist_lutv_first_en bits */
	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
		opmode |= BIT(19) | BIT(20);
		opmode |= (pp_sts->enhist_sts & PP_STS_PA_LUT_FIRST) ?
				BIT(21) : 0;
	} else {
		opmode &= ~(BIT(19) | BIT(21));
		if (!(pp_sts->pa_sts & PP_STS_ENABLE))
			opmode &= ~BIT(20);
	}

	writel_relaxed(opmode, base_addr + PA_OP_MODE_REG_OFF);
}

static int pp_pa_set_config(char __iomem *base_addr,
		struct pp_sts_type *pp_sts, void *cfg_data,
		u32 block_type)
@@ -427,9 +723,15 @@ static void pp_pa_opmode_config(char __iomem *base_addr,
			opmode |= BIT(17);
	}

	/* TODO: reset hist_en, hist_lutv_en and hist_lutv_first_en
	/* reset hist_en, hist_lutv_en and hist_lutv_first_en
	   bits based on the pp_sts
	 */
	if (pp_sts->hist_sts & PP_STS_ENABLE)
		opmode |= BIT(16);
	if (pp_sts->enhist_sts & PP_STS_ENABLE)
		opmode |= BIT(19) | BIT(20);
	if (pp_sts->enhist_sts & PP_STS_PA_LUT_FIRST)
		opmode |= BIT(21);

	writel_relaxed(opmode, base_addr + PA_OP_MODE_REG_OFF);
}