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

Commit 711d4c6f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: Upgrade and fix AD implementation"

parents 0c3af217 38a77943
Loading
Loading
Loading
Loading
+35 −28
Original line number Diff line number Diff line
@@ -720,6 +720,7 @@ static int mdss_fb_probe(struct platform_device *pdev)
	mfd->bl_level = 0;
	mfd->bl_scale = 1024;
	mfd->bl_min_lvl = 30;
	mfd->ad_bl_level = 0;
	mfd->fb_imgType = MDP_RGBA_8888;

	mfd->pdev = pdev;
@@ -1054,10 +1055,9 @@ static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
{
	struct mdss_panel_data *pdata;
	int (*update_ad_input)(struct msm_fb_data_type *mfd);
	u32 temp = bkl_lvl;
	u32 temp = bkl_lvl, ad_bl;
	int ret = -EINVAL;
	bool is_bl_changed = (bkl_lvl != mfd->bl_level);
	bool bl_notify_needed = false;

	/* todo: temporary workaround to support doze mode */
	if ((bkl_lvl == 0) && (mfd->doze_mode)) {
@@ -1077,12 +1077,18 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
	pdata = dev_get_platdata(&mfd->pdev->dev);

	if ((pdata) && (pdata->set_backlight)) {
		if (mfd->mdp.ad_attenuate_bl) {
			ret = (*mfd->mdp.ad_attenuate_bl)(bkl_lvl, &temp, mfd);
			if (ret)
				pr_err("Failed to attenuate BL\n");
		if (mfd->mdp.ad_calc_bl) {
			if (mfd->ad_bl_level == 0)
				mfd->ad_bl_level = temp;
			ad_bl = mfd->ad_bl_level;
			ret = (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp, &ad_bl);
			if ((!ret) && (mfd->ad_bl_level != ad_bl) &&
				mfd->mdp.ad_invalidate_input) {
				mfd->ad_bl_level = ad_bl;
				(*mfd->mdp.ad_invalidate_input)(mfd);
				bl_notify_needed = true;
			}
		}

		if (!IS_CALIB_MODE_BL(mfd))
			mdss_fb_scale_bl(mfd, &temp);
		/*
@@ -1095,20 +1101,14 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
		 */
		if (mfd->bl_level_scaled == temp) {
			mfd->bl_level = bkl_lvl;
			return;
		}
		} else {
			pr_debug("backlight sent to panel :%d\n", temp);
			pdata->set_backlight(pdata, temp);
			mfd->bl_level = bkl_lvl;
			mfd->bl_level_scaled = temp;

		if (mfd->mdp.update_ad_input && is_bl_changed) {
			update_ad_input = mfd->mdp.update_ad_input;
			mutex_unlock(&mfd->bl_lock);
			/* Will trigger ad_setup which will grab bl_lock */
			update_ad_input(mfd);
			mutex_lock(&mfd->bl_lock);
			bl_notify_needed = true;
		}
		if (bl_notify_needed)
			mdss_fb_bl_update_notify(mfd);
	}
}
@@ -1118,6 +1118,7 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
	struct mdss_panel_data *pdata;
	int ret = 0;
	u32 temp;
	u32 ad_bl;

	if (!mfd->unset_bl_level)
		return;
@@ -1127,16 +1128,22 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
		if ((pdata) && (pdata->set_backlight)) {
			mfd->bl_level = mfd->unset_bl_level;
			temp = mfd->bl_level;
			if (mfd->mdp.ad_attenuate_bl) {
				ret = (*mfd->mdp.ad_attenuate_bl)(temp,
						&temp, mfd);
				if (ret)
					pr_err("Failed to attenuate BL\n");
			if (mfd->mdp.ad_calc_bl) {
				if (mfd->ad_bl_level == 0)
					mfd->ad_bl_level = temp;
				ad_bl = mfd->ad_bl_level;
				ret = (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp,
					&ad_bl);
				if ((!ret) && (mfd->ad_bl_level != ad_bl) &&
						mfd->mdp.ad_invalidate_input) {
					mfd->ad_bl_level = ad_bl;
					(*mfd->mdp.ad_invalidate_input)(mfd);
				}
			}

			pdata->set_backlight(pdata, temp);
			mfd->bl_level_scaled = mfd->unset_bl_level;
			mfd->bl_updated = 1;
			mdss_fb_bl_update_notify(mfd);
		}
	}
	mutex_unlock(&mfd->bl_lock);
+7 −3
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@
#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif

#define MDP_PP_AD_BL_LINEAR	0x0
#define MDP_PP_AD_BL_LINEAR_INV	0x1

/**
 * enum mdp_notify_event - Different frame events to indicate frame update state
 *
@@ -147,9 +150,9 @@ struct msm_mdp_interface {
	int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
	int (*do_histogram)(struct msm_fb_data_type *mfd,
				struct mdp_histogram *hist);
	int (*update_ad_input)(struct msm_fb_data_type *mfd);
	int (*ad_attenuate_bl)(u32 bl, u32 *bl_out,
			struct msm_fb_data_type *mfd);
	int (*ad_invalidate_input)(struct msm_fb_data_type *mfd);
	int (*ad_calc_bl)(struct msm_fb_data_type *mfd, int bl_in,
		int *bl_out, int *ad_bl_out);
	int (*panel_register_done)(struct mdss_panel_data *pdata);
	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
	int (*splash_init_fnc)(struct msm_fb_data_type *mfd);
@@ -219,6 +222,7 @@ struct msm_fb_data_type {
	int ext_ad_ctrl;
	u32 ext_bl_ctrl;
	u32 calib_mode;
	u32 ad_bl_level;
	u32 bl_level;
	u32 bl_scale;
	u32 bl_min_lvl;
+1 −1
Original line number Diff line number Diff line
@@ -354,7 +354,6 @@ struct mdss_ad_info {
	u32 last_bl;
	u32 bl_data;
	u32 calc_itr;
	uint32_t bl_bright_shift;
	uint32_t bl_lin[AD_BL_LIN_LEN];
	uint32_t bl_lin_inv[AD_BL_LIN_LEN];
	uint32_t bl_att_lut[AD_BL_ATT_LUT_LEN];
@@ -805,6 +804,7 @@ int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
int mdss_mdp_pp_override_pu(int enable);
int mdss_mdp_pp_overlay_init(struct msm_fb_data_type *mfd);

int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 mixer_num);

+2 −0
Original line number Diff line number Diff line
@@ -3893,6 +3893,8 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
		}
	}

	if (mdss_mdp_pp_overlay_init(mfd))
		pr_warn("Failed to initialize pp overlay data.\n");
	return rc;
init_fail:
	kfree(mdp5_data);
+218 −107
Original line number Diff line number Diff line
@@ -395,10 +395,11 @@ static int pp_read_pa_v2_regs(char __iomem *addr,
				u32 disp_num);
static void pp_read_pa_mem_col_regs(char __iomem *addr,
				struct mdp_pa_mem_col_cfg *mem_col_cfg);
static struct msm_fb_data_type *mdss_get_mfd_from_index(int index);
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
					struct mdss_ad_info **ad);
static int pp_update_ad_input(struct msm_fb_data_type *mfd);
static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd);
static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw,
						struct mdss_ad_info *ad);
@@ -412,8 +413,11 @@ static void pp_ad_bypass_config(struct mdss_ad_info *ad,
				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
static int pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
		struct msm_fb_data_type *mfd);
static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out);
static int pp_ad_linearize_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out,
		int inv);
static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
		int *ad_bl_out);
static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
static inline bool pp_sts_is_enabled(u32 sts, int side);
static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
@@ -1876,6 +1880,7 @@ int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
	struct pp_sts_type pp_sts;
	struct mdss_ad_info *ad;
	struct mdss_data_type *mdata = ctl->mdata;
	struct msm_fb_data_type *bl_mfd;

	if (!mdata)
		return -EPERM;
@@ -1885,36 +1890,6 @@ int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
		return -EINVAL;
	}
	disp_num = ctl->mfd->index;

	if (dspp_num < mdata->nad_cfgs) {
		ret = mdss_mdp_get_ad(ctl->mfd, &ad);
		if (ret)
			return ret;

		if (PP_AD_STATE_CFG & ad->state)
			pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
		if (PP_AD_STATE_INIT & ad->state)
			pp_ad_init_write(&mdata->ad_off[dspp_num], ad, ctl);
		if ((PP_AD_STATE_DATA & ad->state) &&
			(ad->sts & PP_STS_ENABLE)) {
			bl = ad->bl_mfd->bl_level;
			ad->last_bl = bl;
			if (ad->state & PP_AD_STATE_BL_LIN) {
				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
				bl = bl << ad->bl_bright_shift;
				ret = pp_ad_attenuate_bl(bl, &bl, ad->mfd);
				if (ret)
					pr_err("Failed to attenuate BL\n");
			}
			linear_map(bl, &ad->bl_data,
				ad->bl_mfd->panel_info->bl_max,
				MDSS_MDP_AD_BL_SCALE);
			pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
		}
		if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
			ctl->add_vsync_handler(ctl, &ad->handle);
	}

	pp_sts = mdss_pp_res->pp_disp_sts[disp_num];

	if (pp_sts.pa_sts & PP_STS_ENABLE) {
@@ -1983,6 +1958,47 @@ int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)

	mdss_pp_res->pp_disp_flags[disp_num] |= flags;
	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_RESUME_COMMIT;

	if (dspp_num < mdata->nad_cfgs) {
		ret = mdss_mdp_get_ad(ctl->mfd, &ad);
		if (ret) {
			pr_warn("Failed to get AD info, err = %d\n", ret);
			return ret;
		}
		if (ctl->mfd->panel_info->type == WRITEBACK_PANEL) {
			bl_mfd = mdss_get_mfd_from_index(0);
			if (!bl_mfd) {
				ret = -EINVAL;
				pr_warn("Failed to get primary FB bl handle, err = %d\n",
						ret);
				return ret;
			}
		} else {
			bl_mfd = ctl->mfd;
		}

		mutex_lock(&bl_mfd->bl_lock);
		bl = bl_mfd->ad_bl_level;
		mutex_unlock(&bl_mfd->bl_lock);

		mutex_lock(&ad->lock);
		if (PP_AD_STATE_CFG & ad->state)
			pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
		if (PP_AD_STATE_INIT & ad->state)
			pp_ad_init_write(&mdata->ad_off[dspp_num], ad, ctl);
		if ((PP_AD_STATE_DATA & ad->state) &&
			(ad->sts & PP_STS_ENABLE)) {
			ad->last_bl = bl;
			linear_map(bl, &ad->bl_data,
				ad->bl_mfd->panel_info->bl_max,
				MDSS_MDP_AD_BL_SCALE);
			pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
		}
		if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
			ctl->add_vsync_handler(ctl, &ad->handle);
		mutex_unlock(&ad->lock);
	}

	return 0;
}

@@ -2072,6 +2088,80 @@ int mdss_mdp_pp_override_pu(int enable)
	return 0;
}

int mdss_mdp_pp_overlay_init(struct msm_fb_data_type *mfd)
{
	if (!mfd) {
		pr_err("Invalid mfd.\n");
		return -EPERM;
	}

	mfd->mdp.ad_invalidate_input = pp_ad_invalidate_input;
	mfd->mdp.ad_calc_bl = pp_ad_calc_bl;

	return 0;
}

int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
	int *ad_bl_out)
{
	int ret = -1;
	int temp = bl_in;
	struct mdss_ad_info *ad;

	ret = mdss_mdp_get_ad(mfd, &ad);
	if (ret == -ENODEV) {
		pr_debug("AD not supported on device.\n");
		return ret;
	} else if (ret || !ad) {
		pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n",
			ret, ad);
		return ret;
	}

	mutex_lock(&ad->lock);
	if (!(ad->state & PP_AD_STATE_RUN)) {
		pr_debug("AD is not running.\n");
		mutex_unlock(&ad->lock);
		return -EPERM;
	}

	if (!ad->bl_mfd || !ad->bl_mfd->panel_info ||
		!ad->bl_att_lut) {
		pr_err("Invalid ad info: bl_mfd = 0x%p, ad->bl_mfd->panel_info = 0x%p, bl_att_lut = 0x%p\n",
			ad->bl_mfd,
			(!ad->bl_mfd) ? NULL : ad->bl_mfd->panel_info,
			ad->bl_att_lut);
		mutex_unlock(&ad->lock);
		return -EINVAL;
	}

	ret = pp_ad_linearize_bl(ad, bl_in, &temp,
		MDP_PP_AD_BL_LINEAR);
	if (ret) {
		pr_err("Failed to linearize BL: %d\n", ret);
		mutex_unlock(&ad->lock);
		return ret;
	}

	ret = pp_ad_attenuate_bl(ad, temp, &temp);
	if (ret) {
		pr_err("Failed to attenuate BL: %d\n", ret);
		mutex_unlock(&ad->lock);
		return ret;
	}
	*ad_bl_out = temp;

	ret = pp_ad_linearize_bl(ad, temp, &temp, MDP_PP_AD_BL_LINEAR_INV);
	if (ret) {
		pr_err("Failed to inverse linearize BL: %d\n", ret);
		mutex_unlock(&ad->lock);
		return ret;
	}
	*bl_out = temp;
	mutex_unlock(&ad->lock);
	return 0;
}

static int pp_get_dspp_num(u32 disp_num, u32 *dspp_num)
{
	int i;
@@ -4232,34 +4322,42 @@ static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
	return ret;
}

static int pp_update_ad_input(struct msm_fb_data_type *mfd)
/* must call this function from within ad->lock */
static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd)
{
	int ret;
	struct mdss_ad_info *ad;
	struct mdss_ad_input input;
	struct mdss_mdp_ctl *ctl;

	if (!mfd)
	if (!mfd) {
		pr_err("Invalid mfd\n");
		return -EINVAL;
	}
	ctl = mfd_to_ctl(mfd);
	if (!ctl)
	if (!ctl) {
		pr_err("Invalid ctl\n");
		return -EINVAL;
	}

	ret = mdss_mdp_get_ad(mfd, &ad);
	if (ret)
		return ret;
	if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
	if (ret || !ad) {
		pr_err("Fail to get ad: ret = %d, ad = 0x%p\n", ret, ad);
		return -EINVAL;
	}
	pr_debug("AD backlight level changed (%d), trigger update to AD\n",
						mfd->ad_bl_level);
	if (ad->cfg.mode == MDSS_AD_MODE_AUTO_BL) {
		pr_err("AD auto backlight no longer supported.\n");
		return -EINVAL;
	}

	pr_debug("backlight level changed (%d), trigger update to AD\n",
						mfd->bl_level);
	input.mode = ad->cfg.mode;
	if (MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, MDSS_AD_INPUT_AMBIENT))
		input.in.amb_light = ad->ad_data;
	else
		input.in.strength = ad->ad_data;
	/* call to ad_input will trigger backlight read */
	return mdss_mdp_ad_input(mfd, &input, 0);
	if (ad->state & PP_AD_STATE_RUN) {
		ad->calc_itr = ad->cfg.stab_itr;
		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
		ad->sts |= PP_AD_STS_DIRTY_DATA;
	}

	return 0;
}

int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
@@ -4268,7 +4366,7 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
	struct mdss_ad_info *ad;
	struct msm_fb_data_type *bl_mfd;
	int lin_ret = -1, inv_ret = -1, att_ret = -1, ret = 0;
	u32 ratio_temp, shift = 0, last_ops;
	u32 last_ops;

	ret = mdss_mdp_get_ad(mfd, &ad);
	if (ret)
@@ -4301,12 +4399,6 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
				sizeof(uint32_t));
			if (lin_ret || inv_ret)
				ret = -ENOMEM;
			ratio_temp =  mfd->panel_info->bl_max / AD_BL_LIN_LEN;
			while (ratio_temp > 0) {
				ratio_temp = ratio_temp >> 1;
				shift++;
			}
			ad->bl_bright_shift = shift;
		} else {
			ret = -EINVAL;
		}
@@ -4406,7 +4498,7 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
			goto error;
		}
		ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
		pr_debug("ambient = %d", input->in.amb_light);
		pr_debug("ambient = %d\n", input->in.amb_light);
		ad->ad_data = input->in.amb_light;
		ad->calc_itr = ad->cfg.stab_itr;
		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -4425,7 +4517,7 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
			goto error;
		}
		ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
		pr_debug("strength = %d", input->in.strength);
		pr_debug("strength = %d\n", input->in.strength);
		ad->ad_data = input->in.strength;
		ad->calc_itr = ad->cfg.stab_itr;
		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -4725,6 +4817,10 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)

	mdata = mfd_to_mdata(mfd);

	mutex_lock(&bl_mfd->bl_lock);
	bl = bl_mfd->ad_bl_level;
	mutex_unlock(&bl_mfd->bl_lock);

	mutex_lock(&ad->lock);
	if (ad->sts != last_sts || ad->state != last_state) {
		last_sts = ad->sts;
@@ -4741,26 +4837,16 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
		 */
		ad->sts &= ~PP_AD_STS_DIRTY_DATA;
		ad->state |= PP_AD_STATE_DATA;
		mutex_lock(&bl_mfd->bl_lock);
		bl = bl_mfd->bl_level;
		pr_debug("dirty data, last_bl = %d\n", ad->last_bl);
		if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) &&
							(ad->last_bl != bl)) {
			ad->last_bl = bl;
			ad->calc_itr = ad->cfg.stab_itr;
			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
			if (ad->state & PP_AD_STATE_BL_LIN) {
				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
				bl = bl << ad->bl_bright_shift;
				ret = pp_ad_attenuate_bl(bl, &bl, ad->mfd);
				if (ret)
					pr_err("Failed to attenuate BL\n");
			}
			linear_map(bl, &ad->bl_data,
				ad->bl_mfd->panel_info->bl_max,
				MDSS_MDP_AD_BL_SCALE);
		}
		mutex_unlock(&bl_mfd->bl_lock);
		ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
	}

@@ -4804,14 +4890,9 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
		bypass = 0;
		ad->reg_sts |= PP_AD_STS_DIRTY_ENABLE;
		ad->state |= PP_AD_STATE_RUN;
		mutex_lock(&bl_mfd->bl_lock);
		if (bl_mfd != mfd)
			bl_mfd->ext_ad_ctrl = mfd->index;
		bl_mfd->mdp.update_ad_input = pp_update_ad_input;
		bl_mfd->mdp.ad_attenuate_bl = pp_ad_attenuate_bl;
		bl_mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
		mutex_unlock(&bl_mfd->bl_lock);

	} else {
		if (ad->state & PP_AD_STATE_RUN) {
			ad->reg_sts = PP_AD_STS_DIRTY_ENABLE;
@@ -4822,7 +4903,6 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
			ad->state &= !PP_AD_STATE_CFG;
			ad->state &= !PP_AD_STATE_DATA;
			ad->state &= !PP_AD_STATE_BL_LIN;
			ad->bl_bright_shift = 0;
			ad->ad_data = 0;
			ad->ad_data_mode = 0;
			ad->last_bl = 0;
@@ -4836,12 +4916,8 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
				AD_BL_ATT_LUT_LEN);
			memset(&ad->init, 0, sizeof(struct mdss_ad_init));
			memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
			mutex_lock(&bl_mfd->bl_lock);
			bl_mfd->mdp.update_ad_input = NULL;
			bl_mfd->mdp.ad_attenuate_bl = NULL;
			bl_mfd->ext_bl_ctrl = 0;
			bl_mfd->ext_ad_ctrl = -1;
			mutex_unlock(&bl_mfd->bl_lock);
		}
		ad->state &= ~PP_AD_STATE_RUN;
	}
@@ -4883,7 +4959,7 @@ static void pp_ad_calc_worker(struct work_struct *work)
	struct msm_fb_data_type *mfd, *bl_mfd;
	struct mdss_data_type *mdata;
	char __iomem *base;
	u32 bl, calc_done = 0;
	u32 calc_done = 0;
	ad = container_of(work, struct mdss_ad_info, calc_work);

	mutex_lock(&ad->lock);
@@ -4925,22 +5001,8 @@ static void pp_ad_calc_worker(struct work_struct *work)
		if (calc_done) {
			ad->last_str = 0xFF & readl_relaxed(base +
						MDSS_MDP_REG_AD_STR_OUT);
			if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
				bl = 0xFFFF & readl_relaxed(base +
						MDSS_MDP_REG_AD_BL_OUT);
				if (ad->state & PP_AD_STATE_BL_LIN) {
					bl = bl >> ad->bl_bright_shift;
					bl = min_t(u32, bl, (AD_BL_LIN_LEN-1));
					bl = ad->bl_lin_inv[bl];
					bl = bl << ad->bl_bright_shift;
				}
				pr_debug("calc bl = %d\n", bl);
				ad->last_str |= bl << 16;
				mutex_lock(&ad->bl_mfd->bl_lock);
				if (ad->bl_mfd->bl_level)
					mdss_fb_set_backlight(ad->bl_mfd, bl);
				mutex_unlock(&ad->bl_mfd->bl_lock);
			}
			if (MDSS_AD_RUNNING_AUTO_BL(ad))
				pr_err("AD auto backlight no longer supported.\n");
			pr_debug("calc_str = %d, calc_itr %d\n",
							ad->last_str & 0xFF,
							ad->calc_itr);
@@ -4980,25 +5042,17 @@ static void pp_ad_cfg_lut(char __iomem *addr, u32 *data)
			addr + ((PP_AD_LUT_LEN - 1) * 2));
}

static int  pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
	struct msm_fb_data_type *mfd)
/* must call this function from within ad->lock */
static int  pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out)
{
	u32 shift = 0, ratio_temp = 0;
	u32 n, lut_interval, bl_att;
	int ret = -1;
	struct mdss_ad_info *ad;

	if (bl < 0) {
		pr_err("Invalid backlight input\n");
		return ret;
		return -EINVAL;
	}

	ret = mdss_mdp_get_ad(mfd, &ad);
	if (ret || !ad || !ad->bl_mfd || !ad->bl_mfd->panel_info ||
		!ad->bl_mfd->panel_info->bl_max || !ad->bl_att_lut) {
		pr_err("Failed to get the ad.\n");
		return ret;
	}
	pr_debug("bl_in = %d\n", bl);
	/* map panel backlight range to AD backlight range */
	linear_map(bl, &bl, ad->bl_mfd->panel_info->bl_max,
@@ -5013,7 +5067,7 @@ static int pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
	n = bl >> shift;
	if (n >= (AD_BL_ATT_LUT_LEN - 1)) {
		pr_err("Invalid index for BL attenuation: %d.\n", n);
		return ret;
		return -EINVAL;
	}
	lut_interval = (MDSS_MDP_AD_BL_SCALE + 1) / (AD_BL_ATT_LUT_LEN - 1);
	bl_att = ad->bl_att_lut[n] + (bl - lut_interval * n) *
@@ -5036,6 +5090,63 @@ static int pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
	return 0;
}

/* must call this function from within ad->lock */
static int pp_ad_linearize_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out,
	int inv)
{

	u32 n;
	int ret = -EINVAL;

	if (bl < 0 || bl > ad->bl_mfd->panel_info->bl_max) {
		pr_err("Invalid backlight input: bl = %d, bl_max = %d\n", bl,
			ad->bl_mfd->panel_info->bl_max);
		return -EINVAL;
	}

	pr_debug("bl_in = %d, inv = %d\n", bl, inv);

	/* map panel backlight range to AD backlight range */
	linear_map(bl, &bl, ad->bl_mfd->panel_info->bl_max,
		MDSS_MDP_AD_BL_SCALE);

	pr_debug("Before linearization = %d\n", bl);
	n = bl * (AD_BL_LIN_LEN - 1) / MDSS_MDP_AD_BL_SCALE;
	pr_debug("n = %d\n", n);
	if (n > (AD_BL_LIN_LEN - 1)) {
		pr_err("Invalid index for BL linearization: %d.\n", n);
		return ret;
	} else if (n == (AD_BL_LIN_LEN - 1)) {
		if (inv == MDP_PP_AD_BL_LINEAR_INV)
			*bl_out = ad->bl_lin_inv[n];
		else if (inv == MDP_PP_AD_BL_LINEAR)
			*bl_out = ad->bl_lin[n];
	} else {
		/* linear piece-wise interpolation */
		if (inv == MDP_PP_AD_BL_LINEAR_INV) {
			*bl_out = bl * (AD_BL_LIN_LEN - 1) *
				(ad->bl_lin_inv[n + 1] - ad->bl_lin_inv[n]) /
				MDSS_MDP_AD_BL_SCALE - n *
				(ad->bl_lin_inv[n + 1] - ad->bl_lin_inv[n]) +
				ad->bl_lin_inv[n];
		} else if (inv == MDP_PP_AD_BL_LINEAR) {
			*bl_out = bl * (AD_BL_LIN_LEN - 1) *
				(ad->bl_lin[n + 1] - ad->bl_lin[n]) /
				MDSS_MDP_AD_BL_SCALE -
				n * (ad->bl_lin[n + 1] - ad->bl_lin[n]) +
				ad->bl_lin[n];
		}
	}
	pr_debug("After linearization = %d\n", *bl_out);

	/* map AD backlight range back to panel backlight range */
	linear_map(*bl_out, bl_out, MDSS_MDP_AD_BL_SCALE,
		ad->bl_mfd->panel_info->bl_max);

	pr_debug("bl_out = %d\n", *bl_out);
	return 0;
}

int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
{
	u32 i;