msm: mdss: Check valid PP hardware configs based on mfd

The logic for validating the hardware configuration of the mixers, AD
hardware, and DSPPs in a display pipeline has been simplified. If an
incoming PP configuration is invalid and PP hardware is not available,
a warning is printed. Invalid configurations are recoverable, however.

Change-Id: Ib3a6206a8c181390fb6ee5a6761e5ea857b37e1a
Signed-off-by: Benet Clark <benetc@codeaurora.org>
This commit is contained in:
Benet Clark 2015-07-01 12:30:34 -07:00 committed by David Keitel
parent 33896c0d52
commit 87f95cf2a9
4 changed files with 172 additions and 144 deletions

View file

@ -1106,7 +1106,7 @@ int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
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);
int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
@ -1121,6 +1121,8 @@ int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size);
void mdss_hw_init(struct mdss_data_type *mdata);
int mdss_mdp_mfd_valid_dspp(struct msm_fb_data_type *mfd);
int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config, u32 *copyback);
int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
@ -1131,7 +1133,7 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
int mdss_mdp_pp_default_overlay_config(struct msm_fb_data_type *mfd,
struct mdss_panel_data *pdata);
int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback,
int copy_from_kernel);
int copy_from_kernel);
int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en);

View file

@ -3023,9 +3023,7 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
MDSS_MDP_REG_DISP_INTF_SEL);
if (ctl->mixer_left) {
mdss_mdp_pp_resume(ctl, ctl->mixer_left->num);
if (ctl->mixer_right)
mdss_mdp_pp_resume(ctl, ctl->mixer_right->num);
mdss_mdp_pp_resume(ctl->mfd);
if (ctl->panel_data->panel_info.compression_mode ==
COMPRESSION_DSC) {
@ -3113,12 +3111,6 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
}
mixer = ctl->mixer_left;
if (mixer) {
mdss_mdp_pp_resume(ctl, mixer->num);
mixer->params_changed++;
}
temp = readl_relaxed(ctl->mdata->mdp_base +
MDSS_MDP_REG_DISP_INTF_SEL);
temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
@ -3128,7 +3120,9 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
writel_relaxed(temp, ctl->mdata->mdp_base +
MDSS_MDP_REG_DISP_INTF_SEL);
mixer = ctl->mixer_left;
if (mixer) {
mixer->params_changed++;
outsize = (mixer->height << 16) | mixer->width;
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize);
@ -3203,7 +3197,6 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
struct mdss_mdp_mixer *mixer = ctl->mixer_right;
u32 out;
mdss_mdp_pp_resume(ctl, mixer->num);
mixer->params_changed++;
out = (mixer->height << 16) | mixer->width;
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, out);

View file

@ -1367,6 +1367,14 @@ int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
}
}
/* Restore any previously configured PP features by resetting the dirty
* bits for enabled features. The dirty bits will be consumed during the
* first display commit when the PP hardware blocks are updated
*/
rc = mdss_mdp_pp_resume(mfd);
if (rc && (rc != -EPERM) && (rc != -ENODEV))
pr_err("PP resume err %d\n", rc);
/*
* Increment the overlay active count prior to calling ctl_start.
* This is needed to ensure that if idle power collapse kicks in
@ -3532,6 +3540,11 @@ static int mdss_mdp_pp_ioctl(struct msm_fb_data_type *mfd,
mdp_pp.op != mdp_op_calib_dcm_state))
return -EPERM;
if (!mdss_mdp_mfd_valid_dspp(mfd)) {
pr_err("invalid display num %d for PP config\n", mfd->index);
return -EPERM;
}
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
@ -4247,6 +4260,7 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
int rc = 0;
struct mdss_mdp_ctl *ctl;
struct mdss_panel_data *pdata;
struct mdss_overlay_private *mdp5_data;
if (!mfd)
return ERR_PTR(-EINVAL);
@ -4258,6 +4272,12 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
goto error;
}
mdp5_data = mfd_to_mdp5_data(mfd);
if (!mdp5_data) {
rc = -EINVAL;
goto error;
}
ctl = mdss_mdp_ctl_init(pdata, mfd);
if (IS_ERR_OR_NULL(ctl)) {
pr_err("Unable to initialize ctl for fb%d\n",
@ -4285,10 +4305,12 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
}
}
mdp5_data->ctl = ctl;
rc = mdss_mdp_pp_default_overlay_config(mfd, pdata);
if (rc) {
pr_err("Unable to set default postprocessing configs for fb%d\n",
mfd->index);
pr_err("Unable to set default postprocessing configs for fb%d ret %d\n",
mfd->index, rc);
rc = 0;
}
@ -4319,7 +4341,6 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
ctl = __mdss_mdp_overlay_ctl_init(mfd);
if (IS_ERR_OR_NULL(ctl))
return PTR_ERR(ctl);
mdp5_data->ctl = ctl;
} else {
ctl = mdp5_data->ctl;
}
@ -4334,7 +4355,7 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
if (mdss_fb_is_power_on(mfd)) {
pr_debug("panel was never turned off\n");
rc = mdss_mdp_ctl_start(mdp5_data->ctl, false);
rc = mdss_mdp_ctl_start(ctl, false);
goto panel_on;
}
@ -4348,7 +4369,7 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
rc = mdss_mdp_overlay_kickoff(mfd, NULL);
}
} else {
rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
rc = mdss_mdp_ctl_setup(ctl);
if (rc)
goto end;
}
@ -4563,7 +4584,6 @@ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd)
rc = PTR_ERR(ctl);
goto error;
}
mdp5_data->ctl = ctl;
} else {
ctl = mdp5_data->ctl;
}

View file

@ -364,7 +364,7 @@ static int pp_read_pa_v2_regs(char __iomem *addr,
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_mfd_valid_ad(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_ad_invalidate_input(struct msm_fb_data_type *mfd);
@ -391,7 +391,8 @@ static int pp_update_pcc_pipe_setup(struct mdss_mdp_pipe *pipe, u32 location);
static void mdss_mdp_hist_irq_set_mask(u32 irq);
static void mdss_mdp_hist_irq_clear_mask(u32 irq);
static void mdss_mdp_hist_intr_notify(u32 disp);
static int mdss_mdp_panel_default_dither_config(u32 panel_bpp, u32 disp_num);
static int mdss_mdp_panel_default_dither_config(struct msm_fb_data_type *mfd,
u32 panel_bpp);
static u32 last_sts, last_state;
@ -2048,28 +2049,26 @@ exit:
* Set dirty and write bits on features that were enabled so they will be
* reconfigured
*/
int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd)
{
u32 flags = 0, disp_num, bl, ret = 0;
u32 flags = 0, disp_num, ret = 0;
struct pp_sts_type pp_sts;
struct mdss_ad_info *ad;
struct mdss_data_type *mdata;
struct msm_fb_data_type *bl_mfd;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
struct mdp_pa_v2_cfg_data *pa_v2_cache_cfg = NULL;
if (!ctl || !ctl->mdata || !ctl->mfd) {
pr_err("invalid input: ctl = 0x%p, mdata = 0x%p, mfd = 0x%p\n",
ctl, (!ctl) ? NULL : ctl->mdata,
(!ctl) ? NULL : ctl->mfd);
if (!mfd) {
pr_err("invalid input: mfd = 0x%p\n", mfd);
return -EINVAL;
}
if (!mdss_mdp_mfd_valid_dspp(mfd)) {
pr_warn("PP not supported on display num %d hw config\n",
mfd->index);
return -EPERM;
}
mdata = ctl->mdata;
if (dspp_num >= mdata->ndspp) {
pr_err("invalid dspp_num %d\n", dspp_num);
return -EINVAL;
}
disp_num = ctl->mfd->index;
disp_num = mfd->index;
pp_sts = mdss_pp_res->pp_disp_sts[disp_num];
if (pp_sts.pa_sts & PP_STS_ENABLE) {
@ -2143,43 +2142,27 @@ 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(&ad->lock);
bl = bl_mfd->ad_bl_level;
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,
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->ops.add_vsync_handler(ctl, &ad->handle);
mutex_unlock(&ad->lock);
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret == -ENODEV || ret == -EPERM) {
pr_debug("AD not supported on device, disp num %d\n",
mfd->index);
return 0;
} 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 (PP_AD_STATE_CFG & ad->state)
ad->sts |= PP_AD_STS_DIRTY_CFG;
if (PP_AD_STATE_INIT & ad->state)
ad->sts |= PP_AD_STS_DIRTY_INIT;
if ((PP_AD_STATE_DATA & ad->state) &&
(ad->sts & PP_STS_ENABLE))
ad->sts |= PP_AD_STS_DIRTY_DATA;
mutex_unlock(&ad->lock);
return 0;
}
@ -2437,8 +2420,7 @@ int mdss_mdp_pp_default_overlay_config(struct msm_fb_data_type *mfd,
return -EINVAL;
}
ret = mdss_mdp_panel_default_dither_config(pdata->panel_info.bpp,
mfd->index);
ret = mdss_mdp_panel_default_dither_config(mfd, pdata->panel_info.bpp);
if (ret)
pr_err("Unable to configure default dither on fb%d\n",
mfd->index);
@ -2455,9 +2437,10 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
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;
if (ret == -ENODEV || ret == -EPERM) {
pr_debug("AD not supported on device, disp num %d\n",
mfd->index);
return 0;
} else if (ret || !ad) {
pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n",
ret, ad);
@ -3092,6 +3075,12 @@ int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
if (!ctl)
return -EINVAL;
if (!mdss_mdp_mfd_valid_dspp(ctl->mfd)) {
pr_warn("IGC not supported on display num %d hw configuration\n",
ctl->mfd->index);
return 0;
}
config.len = IGC_LUT_ENTRIES;
config.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
config.block = (ctl->mfd->index) + MDP_LOGICAL_BLOCK_DISP_0;
@ -3633,19 +3622,23 @@ enhist_config_exit:
return ret;
}
static int mdss_mdp_panel_default_dither_config(u32 panel_bpp, u32 disp_num)
static int mdss_mdp_panel_default_dither_config(struct msm_fb_data_type *mfd,
u32 panel_bpp)
{
int ret = 0;
struct mdp_dither_cfg_data dither = {
.block = disp_num + MDP_LOGICAL_BLOCK_DISP_0,
.flags = MDP_PP_OPS_DISABLE,
};
struct mdp_dither_cfg_data dither;
struct mdp_pp_feature_version dither_version = {
.pp_feature = DITHER,
};
struct mdp_dither_data_v1_7 dither_data;
dither.block = disp_num + MDP_LOGICAL_BLOCK_DISP_0;
if (!mdss_mdp_mfd_valid_dspp(mfd)) {
pr_warn("dither config not supported on display num %d\n",
mfd->index);
return 0;
}
dither.block = mfd->index + MDP_LOGICAL_BLOCK_DISP_0;
dither.flags = MDP_PP_OPS_DISABLE;
ret = mdss_mdp_pp_get_version(&dither_version);
@ -4803,67 +4796,42 @@ static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
return -EINVAL;
}
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 **ret_ad)
{
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 mixer_num;
u32 ret = -EINVAL;
int i = 0;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
struct msm_fb_data_type *ad_mfd = mfd;
int ret = 0;
struct mdss_data_type *mdata;
struct mdss_mdp_ctl *ctl = NULL;
if (ad_mfd->ext_ad_ctrl >= 0)
ad_mfd = mdss_get_mfd_from_index(ad_mfd->ext_ad_ctrl);
if (!ad_mfd || !mdata)
return ret;
*ret_ad = NULL;
if (!mfd) {
pr_err("invalid parameter mfd %p\n", mfd);
return -EINVAL;
}
mdata = mfd_to_mdata(mfd);
if (mdata->nad_cfgs == 0) {
pr_debug("Assertive Display not supported by device\n");
return -ENODEV;
}
if (ad_mfd->panel_info->type == DTV_PANEL) {
if (!mdss_mdp_mfd_valid_ad(mfd)) {
pr_warn("AD not supported on display num %d hw config\n",
mfd->index);
return -EPERM;
}
if (mfd->panel_info->type == DTV_PANEL) {
pr_debug("AD not supported on external display\n");
return ret;
return -EPERM;
}
mixer_num = mdss_mdp_get_ctl_mixers(ad_mfd->index, mixer_id);
if (!mixer_num) {
pr_debug("no mixers connected, %d\n", mixer_num);
return -EHOSTDOWN;
}
if (mixer_num > mdata->nmax_concurrent_ad_hw) {
pr_debug("too many mixers, not supported, %d > %d\n", mixer_num,
mdata->nmax_concurrent_ad_hw);
return ret;
}
do {
if (mixer_id[i] >= mdata->nad_cfgs) {
pr_err("invalid mixer input, %d\n", mixer_id[i]);
return ret;
}
i++;
} while (i < mixer_num);
return mixer_id[0];
}
static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
struct mdss_ad_info **ret_ad)
{
int ad_num, ret = 0;
struct mdss_data_type *mdata;
struct mdss_ad_info *ad = NULL;
mdata = mfd_to_mdata(mfd);
ad_num = mdss_ad_init_checks(mfd);
if (ad_num >= 0)
ad = &mdata->ad_cfgs[ad_num];
ctl = mfd_to_ctl(mfd);
if ((ctl) && (ctl->mixer_left))
*ret_ad = &mdata->ad_cfgs[ctl->mixer_left->num];
else
ret = ad_num;
*ret_ad = ad;
ret = -EPERM;
return ret;
}
@ -4872,22 +4840,21 @@ static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd)
{
int ret;
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
if (!mfd) {
pr_err("Invalid mfd\n");
return -EINVAL;
}
ctl = mfd_to_ctl(mfd);
if (!ctl) {
pr_err("Invalid ctl\n");
return -EINVAL;
}
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret || !ad) {
pr_err("Fail to get ad: ret = %d, ad = 0x%p\n", ret, ad);
return -EINVAL;
if (ret == -ENODEV || ret == -EPERM) {
pr_debug("AD not supported on device, disp num %d\n",
mfd->index);
return 0;
} else if (ret || !ad) {
pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n",
ret, ad);
return ret;
}
pr_debug("AD backlight level changed (%d), trigger update to AD\n",
mfd->ad_bl_level);
@ -4914,8 +4881,15 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
u32 last_ops;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret)
if (ret == -ENODEV || ret == -EPERM) {
pr_err("AD not supported on device, disp num %d\n",
mfd->index);
return ret;
} else if (ret || !ad) {
pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n",
ret, ad);
return ret;
}
if (mfd->panel_info->type == WRITEBACK_PANEL) {
bl_mfd = mdss_get_mfd_from_index(0);
if (!bl_mfd)
@ -5018,8 +4992,15 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
u32 bl;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret)
if (ret == -ENODEV || ret == -EPERM) {
pr_err("AD not supported on device, disp num %d\n",
mfd->index);
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 ((!PP_AD_STATE_IS_INITCFG(ad->state) &&
@ -5344,10 +5325,14 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret) {
ret = -EINVAL;
pr_debug("failed to get ad_info, err = %d\n", ret);
goto exit;
if (ret == -ENODEV || ret == -EPERM) {
pr_debug("AD not supported on device, disp num %d\n",
mfd->index);
return 0;
} else if (ret || !ad) {
pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n",
ret, ad);
return ret;
}
if (mfd->panel_info->type == WRITEBACK_PANEL) {
bl_mfd = mdss_get_mfd_from_index(0);
@ -6510,3 +6495,31 @@ void mdss_mdp_free_layer_pp_info(struct mdp_input_layer *layer)
kfree(pp_info->pcc_cfg_data.cfg_payload);
kfree(pp_info);
}
int mdss_mdp_mfd_valid_dspp(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_ctl *ctl = NULL;
int valid_dspp = false;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
ctl = mfd_to_ctl(mfd);
valid_dspp = (ctl) && (ctl->mixer_left) &&
(ctl->mixer_left->num < mdata->ndspp);
if ((ctl) && (ctl->mixer_right))
valid_dspp &= (ctl->mixer_right->num < mdata->ndspp);
return valid_dspp;
}
static int mdss_mdp_mfd_valid_ad(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_ctl *ctl = NULL;
int valid_ad = false;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
ctl = mfd_to_ctl(mfd);
valid_ad = (ctl) && (ctl->mixer_left) &&
(ctl->mixer_left->num < mdata->nad_cfgs);
if ((ctl) && (ctl->mixer_right))
valid_ad &= (ctl->mixer_right->num < mdata->nad_cfgs);
return valid_ad;
}