msm: mdss: workaround for bwc and panic
Due to HW problem, when BWC is enabled, panic is asserted continuously as long as pipe with BWC decode is fetching from the memory. This continuous panic assertion causes unnecessary CPU throttling and causes lot of side effects. To prevent the issues related to HW problem, disable BWC on video mode panels on msm8994. On CMD mode panels, use BWC but disable panic signal as long as there is no video mode secondary display. It is user-space's responsibility to not use BWC when primary display is CMD mode but any kind of secondary video mode display is active. Change-Id: Idb219e61599d2e2564bd4076fcfc787cd99c8d4d Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org> [mattw@codeaurora.org: resolved a trivial context conflict in mdss.h] Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
This commit is contained in:
parent
1e40a94776
commit
e509f3b8cb
7 changed files with 125 additions and 22 deletions
|
@ -26,6 +26,7 @@
|
|||
#include "mdss_panel.h"
|
||||
|
||||
#define MAX_DRV_SUP_MMB_BLKS 44
|
||||
#define MAX_DRV_SUP_PIPES 10
|
||||
|
||||
#define MDSS_PINCTRL_STATE_DEFAULT "mdss_default"
|
||||
#define MDSS_PINCTRL_STATE_SLEEP "mdss_sleep"
|
||||
|
@ -125,6 +126,11 @@ struct mdss_pp_block_off {
|
|||
u32 dspp_pgc_off;
|
||||
};
|
||||
|
||||
enum mdss_hw_quirk {
|
||||
MDSS_QUIRK_BWCPANIC,
|
||||
MDSS_QUIRK_MAX,
|
||||
};
|
||||
|
||||
struct mdss_data_type {
|
||||
u32 mdp_rev;
|
||||
struct clk *mdp_clk[MDSS_MAX_CLK];
|
||||
|
@ -143,7 +149,18 @@ struct mdss_data_type {
|
|||
|
||||
struct mutex reg_lock;
|
||||
|
||||
/* bitmap to track pipes that have BWC enabled */
|
||||
DECLARE_BITMAP(bwc_enable_map, MAX_DRV_SUP_PIPES);
|
||||
/* bitmap to track hw workarounds */
|
||||
DECLARE_BITMAP(mdss_quirk_map, MDSS_QUIRK_MAX);
|
||||
/* bitmap to track total mmbs in use */
|
||||
DECLARE_BITMAP(mmb_alloc_map, MAX_DRV_SUP_MMB_BLKS);
|
||||
|
||||
u32 has_bwc;
|
||||
u32 default_panic_lut0;
|
||||
u32 default_panic_lut1;
|
||||
u32 default_robust_lut;
|
||||
|
||||
u32 has_decimation;
|
||||
bool has_fixed_qos_arbiter_enabled;
|
||||
bool has_panic_ctrl;
|
||||
|
@ -218,8 +235,6 @@ struct mdss_data_type {
|
|||
u8 ncursor_pipes;
|
||||
u32 max_cursor_size;
|
||||
|
||||
DECLARE_BITMAP(mmb_alloc_map, MAX_DRV_SUP_MMB_BLKS);
|
||||
|
||||
struct mdss_mdp_mixer *mixer_intf;
|
||||
struct mdss_mdp_mixer *mixer_wb;
|
||||
u32 nmixers_intf;
|
||||
|
@ -335,6 +350,18 @@ static inline int mdss_get_sd_client_cnt(void)
|
|||
return atomic_read(&mdss_res->sd_client_count);
|
||||
}
|
||||
|
||||
static inline void mdss_set_quirk(struct mdss_data_type *mdata,
|
||||
enum mdss_hw_quirk bit)
|
||||
{
|
||||
set_bit(bit, mdata->mdss_quirk_map);
|
||||
}
|
||||
|
||||
static inline bool mdss_has_quirk(struct mdss_data_type *mdata,
|
||||
enum mdss_hw_quirk bit)
|
||||
{
|
||||
return test_bit(bit, mdata->mdss_quirk_map);
|
||||
}
|
||||
|
||||
#define MDSS_VBIF_WRITE(mdata, offset, value, nrt_vbif) \
|
||||
(nrt_vbif ? dss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\
|
||||
dss_reg_w(&mdata->vbif_io, offset, value, 0))
|
||||
|
|
|
@ -71,7 +71,6 @@ static int mdss_fb_mem_get_iommu_domain(void)
|
|||
struct msm_mdp_interface mdp5 = {
|
||||
.init_fnc = mdss_mdp_overlay_init,
|
||||
.fb_mem_get_iommu_domain = mdss_fb_mem_get_iommu_domain,
|
||||
.panel_register_done = mdss_panel_register_done,
|
||||
.fb_stride = mdss_mdp_fb_stride,
|
||||
.check_dsi_status = mdss_check_dsi_ctrl_status,
|
||||
};
|
||||
|
@ -1096,6 +1095,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
|
|||
case MDSS_MDP_HW_REV_105:
|
||||
case MDSS_MDP_HW_REV_109:
|
||||
case MDSS_MDP_HW_REV_110:
|
||||
mdss_set_quirk(mdata, MDSS_QUIRK_BWCPANIC);
|
||||
mdata->max_target_zorder = MDSS_MDP_MAX_STAGE;
|
||||
mdata->max_cursor_size = 128;
|
||||
break;
|
||||
|
@ -1112,7 +1112,6 @@ static void mdss_hw_rev_init(struct mdss_data_type *mdata)
|
|||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
mdata->mdp_rev = MDSS_REG_READ(mdata, MDSS_REG_HW_VERSION);
|
||||
pr_info_once("MDP Rev=%x\n", mdata->mdp_rev);
|
||||
mdss_mdp_hw_rev_caps_init(mdata);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
}
|
||||
|
@ -1125,7 +1124,7 @@ static void mdss_hw_rev_init(struct mdss_data_type *mdata)
|
|||
* parameters. This function does not explicitly turn on the MDP clocks
|
||||
* and so it must be called with the MDP clocks already enabled.
|
||||
*/
|
||||
int mdss_hw_init(struct mdss_data_type *mdata)
|
||||
void mdss_hw_init(struct mdss_data_type *mdata)
|
||||
{
|
||||
int i, j;
|
||||
char *offset;
|
||||
|
@ -1174,8 +1173,6 @@ int mdss_hw_init(struct mdss_data_type *mdata)
|
|||
mdss_mdp_hscl_init(&vig[i]);
|
||||
|
||||
pr_debug("MDP hw init done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
|
||||
|
@ -1228,13 +1225,11 @@ void mdss_mdp_footswitch_ctrl_splash(int on)
|
|||
if (mdata != NULL) {
|
||||
if (on) {
|
||||
pr_debug("Enable MDP FS for splash.\n");
|
||||
mdata->handoff_pending = true;
|
||||
ret = regulator_enable(mdata->fs);
|
||||
if (ret)
|
||||
pr_err("Footswitch failed to enable\n");
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
mdss_hw_init(mdata);
|
||||
} else {
|
||||
pr_debug("Disable MDP FS for splash.\n");
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
|
@ -1445,6 +1440,7 @@ static int mdss_mdp_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int rc;
|
||||
struct mdss_data_type *mdata;
|
||||
bool display_on;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
pr_err("MDP driver only supports device tree probe\n");
|
||||
|
@ -1579,6 +1575,34 @@ static int mdss_mdp_probe(struct platform_device *pdev)
|
|||
if (rc)
|
||||
pr_err("mdss_register_irq failed.\n");
|
||||
mdss_res->mdss_util->mdp_probe_done = true;
|
||||
|
||||
/*
|
||||
* enable clocks and read mdp_rev as soon as possible once
|
||||
* kernel is up. Read the DISP_INTF_SEL register to check if
|
||||
* display was enabled in bootloader or not. If yes, let handoff
|
||||
* handle removing the extra clk/regulator votes else turn off
|
||||
* clk/regulators because purpose here is to get mdp_rev.
|
||||
*/
|
||||
mdss_mdp_footswitch_ctrl_splash(true);
|
||||
mdss_hw_init(mdata);
|
||||
display_on = (bool)readl_relaxed(mdata->mdp_base +
|
||||
MDSS_MDP_REG_DISP_INTF_SEL);
|
||||
if (!display_on)
|
||||
mdss_mdp_footswitch_ctrl_splash(false);
|
||||
else
|
||||
mdata->handoff_pending = true;
|
||||
|
||||
pr_info("mdss version = 0x%x, bootloader display is %s\n",
|
||||
mdata->mdp_rev, display_on ? "on" : "off");
|
||||
|
||||
if (mdss_has_quirk(mdata, MDSS_QUIRK_BWCPANIC)) {
|
||||
mdata->default_panic_lut0 = readl_relaxed(mdata->mdp_base +
|
||||
MMSS_MDP_PANIC_LUT0);
|
||||
mdata->default_panic_lut1 = readl_relaxed(mdata->mdp_base +
|
||||
MMSS_MDP_PANIC_LUT1);
|
||||
mdata->default_robust_lut = readl_relaxed(mdata->mdp_base +
|
||||
MMSS_MDP_ROBUST_LUT);
|
||||
}
|
||||
probe_done:
|
||||
if (IS_ERR_VALUE(rc)) {
|
||||
if (mdata->regulator_notif_register)
|
||||
|
|
|
@ -889,7 +889,7 @@ int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
|
|||
void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size);
|
||||
|
||||
int mdss_hw_init(struct mdss_data_type *mdata);
|
||||
void mdss_hw_init(struct mdss_data_type *mdata);
|
||||
|
||||
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);
|
||||
|
@ -945,6 +945,7 @@ int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
|
|||
|
||||
int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable);
|
||||
void mdss_mdp_bwcpanic_ctrl(struct mdss_data_type *mdata, bool enable);
|
||||
int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
|
||||
struct mdss_mdp_data *src_data);
|
||||
|
@ -983,7 +984,6 @@ u32 mdss_mdp_get_mixercfg(struct mdss_mdp_mixer *mixer);
|
|||
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
|
||||
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval);
|
||||
|
||||
int mdss_panel_register_done(struct mdss_panel_data *pdata);
|
||||
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
|
||||
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
|
||||
int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
|
||||
|
|
|
@ -3355,6 +3355,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
|
|||
int ret = 0;
|
||||
bool is_bw_released;
|
||||
int split_enable;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
if (!ctl) {
|
||||
pr_err("display function not set\n");
|
||||
|
@ -3481,6 +3482,10 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
|
|||
commit_cb->commit_cb_fnc(MDP_COMMIT_STAGE_READY_FOR_KICKOFF,
|
||||
commit_cb->data);
|
||||
|
||||
if (mdss_has_quirk(mdata, MDSS_QUIRK_BWCPANIC) &&
|
||||
!bitmap_empty(mdata->bwc_enable_map, MAX_DRV_SUP_PIPES))
|
||||
mdss_mdp_bwcpanic_ctrl(mdata, true);
|
||||
|
||||
ATRACE_BEGIN("flush_kickoff");
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
|
||||
if (sctl && sctl->flush_bits) {
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#define MMSS_MDP_MDP_SSPP_SPARE_0 0x00028
|
||||
|
||||
#define MMSS_MDP_PANIC_ROBUST_CTRL 0x00178
|
||||
#define MMSS_MDP_PANIC_LUT0 0x0017C
|
||||
#define MMSS_MDP_PANIC_LUT1 0x00180
|
||||
#define MMSS_MDP_ROBUST_LUT 0x00184
|
||||
#define MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL 0x00190
|
||||
|
||||
#define MDSS_MDP_REG_VIDEO_INTF_UNDERFLOW_CTL 0x002E0
|
||||
|
|
|
@ -3625,14 +3625,6 @@ ctl_stop:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int mdss_panel_register_done(struct mdss_panel_data *pdata)
|
||||
{
|
||||
if (pdata->panel_info.cont_splash_enabled)
|
||||
mdss_mdp_footswitch_ctrl_splash(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __mdss_mdp_ctl_handoff(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_data_type *mdata)
|
||||
{
|
||||
|
@ -3921,7 +3913,6 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
|
|||
mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
|
||||
mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
|
||||
mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
|
||||
mdp5_interface->panel_register_done = mdss_panel_register_done;
|
||||
mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
|
||||
mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
|
||||
mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
|
||||
|
@ -3965,6 +3956,14 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* disable BWC if primary panel is video mode on specific
|
||||
* chipsets to workaround HW problem.
|
||||
*/
|
||||
if (mdss_has_quirk(mdp5_data->mdata, MDSS_QUIRK_BWCPANIC) &&
|
||||
mfd->panel_info->type == MIPI_VIDEO_PANEL && (0 == mfd->index))
|
||||
mdp5_data->mdata->has_bwc = false;
|
||||
|
||||
mfd->panel_orientation = mfd->panel_info->panel_orientation;
|
||||
|
||||
if ((mfd->panel_info->panel_orientation & MDP_FLIP_LR) &&
|
||||
|
|
|
@ -66,6 +66,7 @@ int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
|
|||
if (!mdata->has_panic_ctrl)
|
||||
goto end;
|
||||
|
||||
mutex_lock(&mdata->reg_lock);
|
||||
switch (mdss_mdp_panic_signal_support_mode(mdata, pipe)) {
|
||||
case MDSS_MDP_PANIC_COMMON_REG_CFG:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
|
@ -92,11 +93,33 @@ int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
|
|||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&mdata->reg_lock);
|
||||
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdss_mdp_bwcpanic_ctrl(struct mdss_data_type *mdata, bool enable)
|
||||
{
|
||||
if (!mdata)
|
||||
return;
|
||||
|
||||
mutex_lock(&mdata->reg_lock);
|
||||
if (enable) {
|
||||
writel_relaxed(0x0, mdata->mdp_base + MMSS_MDP_PANIC_LUT0);
|
||||
writel_relaxed(0x0, mdata->mdp_base + MMSS_MDP_PANIC_LUT1);
|
||||
writel_relaxed(0x0, mdata->mdp_base + MMSS_MDP_ROBUST_LUT);
|
||||
} else {
|
||||
writel_relaxed(mdata->default_panic_lut0,
|
||||
mdata->mdp_base + MMSS_MDP_PANIC_LUT0);
|
||||
writel_relaxed(mdata->default_panic_lut1,
|
||||
mdata->mdp_base + MMSS_MDP_PANIC_LUT1);
|
||||
writel_relaxed(mdata->default_robust_lut,
|
||||
mdata->mdp_base + MMSS_MDP_ROBUST_LUT);
|
||||
}
|
||||
mutex_unlock(&mdata->reg_lock);
|
||||
}
|
||||
|
||||
static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata,
|
||||
struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
|
@ -1010,14 +1033,15 @@ struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
|
|||
static void mdss_mdp_pipe_free(struct kref *kref)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
pipe = container_of(kref, struct mdss_mdp_pipe, kref);
|
||||
|
||||
pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
mdss_mdp_pipe_panic_signal_ctrl(pipe, false);
|
||||
|
||||
mdss_mdp_pipe_panic_signal_ctrl(pipe, false);
|
||||
if (pipe->play_cnt) {
|
||||
mdss_mdp_pipe_fetch_halt(pipe);
|
||||
mdss_mdp_pipe_sspp_term(pipe);
|
||||
|
@ -1025,12 +1049,22 @@ static void mdss_mdp_pipe_free(struct kref *kref)
|
|||
} else {
|
||||
mdss_mdp_smp_unreserve(pipe);
|
||||
}
|
||||
if (mdss_has_quirk(mdata, MDSS_QUIRK_BWCPANIC) && pipe->bwc_mode) {
|
||||
unsigned long pnum_bitmap = BIT(pipe->num);
|
||||
bitmap_andnot(mdata->bwc_enable_map, mdata->bwc_enable_map,
|
||||
&pnum_bitmap, MAX_DRV_SUP_PIPES);
|
||||
pipe->bwc_mode = 0;
|
||||
|
||||
if (bitmap_empty(mdata->bwc_enable_map, MAX_DRV_SUP_PIPES))
|
||||
mdss_mdp_bwcpanic_ctrl(mdata, false);
|
||||
}
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
|
||||
pipe->flags = 0;
|
||||
pipe->is_right_blend = false;
|
||||
pipe->src_split_req = false;
|
||||
pipe->bwc_mode = 0;
|
||||
|
||||
pipe->mfd = NULL;
|
||||
pipe->mixer_left = pipe->mixer_right = NULL;
|
||||
memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
|
||||
|
@ -1724,6 +1758,17 @@ update_nobuf:
|
|||
|
||||
pipe->play_cnt++;
|
||||
|
||||
if (mdss_has_quirk(mdata, MDSS_QUIRK_BWCPANIC)) {
|
||||
unsigned long pnum_bitmap = BIT(pipe->num);
|
||||
if (pipe->bwc_mode)
|
||||
bitmap_or(mdata->bwc_enable_map, mdata->bwc_enable_map,
|
||||
&pnum_bitmap, MAX_DRV_SUP_PIPES);
|
||||
else
|
||||
bitmap_andnot(mdata->bwc_enable_map,
|
||||
mdata->bwc_enable_map, &pnum_bitmap,
|
||||
MAX_DRV_SUP_PIPES);
|
||||
}
|
||||
|
||||
done:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue