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

Commit 38a77943 authored by Ping Li's avatar Ping Li Committed by Ping Li
Browse files

msm: mdss: Upgrade and fix AD implementation



Clean up the ad lock and bl_lock to avoid potential deadlock, and
remove no longer needed code for assertive display, including extra
AD parameter setup triggered by backlight change, auto backlight mode
support. Also change the AD backlight linearization LUT from 8 bit to
12 bit values and upgrade the mapping from point to point mapping to
piecewise linear mapping.

Change-Id: Iac4e3de0f96f24ece4220dc740d781324265ffa8
Signed-off-by: default avatarPing Li <quicpingli@codeaurora.org>
parent 156aa1e4
Loading
Loading
Loading
Loading
+35 −28
Original line number Diff line number Diff line
@@ -717,6 +717,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;
@@ -1051,10 +1052,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)) {
@@ -1074,12 +1074,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);
		/*
@@ -1092,20 +1098,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);
	}
}
@@ -1115,6 +1115,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;
@@ -1124,16 +1125,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;