msm: mdss: refactor split mode specific code
MDSS HW can support different variants of split modes and each one is unique based on specific needs. Refactor current implementation such that terminology for each split is easily understood. Along with this, enable single DSI split layer mixer configuration which can be used to save power because it reduces MDP's core clock. Following are the currently supported split modes. * split_none: single ctl with single lm and single display interface. i.e. 1080p/720p single dsi, single lm config. * dual_lm_single_display: single ctl with split lm and single display interface. i.e. WQXGA eDP or 4K HDMI or 1080p single dsi, split lm. * dual_lm_dual_display: synchronized dual ctl with dual lm and dual display interfaces. i.e. WQXGA dual-DSI or 4K dual-DSI * pingpong_split_dual_display: single ctl path with single lm but two synchronized display interfaces. Split is done after pingpong HW module. i.e WQXGA dual-dsi on msm8939/msm8992 etc. Change-Id: I3edcc0c056cc2a1a76a819f0892035a10730118d Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
This commit is contained in:
parent
d742011534
commit
ffaf975ec3
8 changed files with 85 additions and 54 deletions
|
@ -171,7 +171,7 @@ struct mdss_data_type {
|
|||
u8 has_non_scalar_rgb;
|
||||
bool has_src_split;
|
||||
bool idle_pc_enabled;
|
||||
bool has_dst_split;
|
||||
bool has_pingpong_split;
|
||||
bool has_pixel_ram;
|
||||
bool needs_hist_vote;
|
||||
|
||||
|
|
|
@ -301,6 +301,11 @@ static inline int mdss_fb_validate_split(int left, int right,
|
|||
{
|
||||
int rc = -EINVAL;
|
||||
u32 panel_xres = mdss_fb_get_panel_xres(mfd->panel_info);
|
||||
|
||||
pr_debug("%pS: split_mode = %d left=%d right=%d panel_xres=%d\n",
|
||||
__builtin_return_address(0), mfd->split_mode,
|
||||
left, right, panel_xres);
|
||||
|
||||
/* more validate condition could be added if needed */
|
||||
if (left && right) {
|
||||
if (panel_xres == left + right) {
|
||||
|
@ -309,7 +314,7 @@ static inline int mdss_fb_validate_split(int left, int right,
|
|||
rc = 0;
|
||||
}
|
||||
} else {
|
||||
if (is_split_lm(mfd)) {
|
||||
if (mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
|
||||
mfd->split_fb_left = mfd->panel_info->xres;
|
||||
mfd->split_fb_right = panel_xres - mfd->split_fb_left;
|
||||
rc = 0;
|
||||
|
@ -330,7 +335,8 @@ static void mdss_fb_parse_dt_split(struct msm_fb_data_type *mfd)
|
|||
"qcom,mdss-fb-split", data, 2);
|
||||
|
||||
if (!mdss_fb_validate_split(data[0], data[1], mfd))
|
||||
pr_debug("dt split_left=%d split_right=%d\n", data[0], data[1]);
|
||||
pr_info_once("device tree split left=%d right=%d\n",
|
||||
data[0], data[1]);
|
||||
}
|
||||
|
||||
static ssize_t mdss_fb_store_split(struct device *dev,
|
||||
|
@ -370,9 +376,28 @@ static void mdss_fb_get_split(struct msm_fb_data_type *mfd)
|
|||
if (!mfd->mdss_fb_split_stored)
|
||||
mdss_fb_parse_dt_split(mfd);
|
||||
|
||||
if (mfd->split_fb_left || mfd->split_fb_right)
|
||||
pr_debug("split framebuffer left=%d right=%d\n",
|
||||
mfd->split_fb_left, mfd->split_fb_right);
|
||||
if ((mfd->split_mode == MDP_SPLIT_MODE_NONE) &&
|
||||
(mfd->split_fb_left || mfd->split_fb_right))
|
||||
mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY;
|
||||
|
||||
pr_debug("split framebuffer left=%d right=%d mode=%d\n",
|
||||
mfd->split_fb_left, mfd->split_fb_right, mfd->split_mode);
|
||||
}
|
||||
|
||||
static ssize_t mdss_fb_get_src_split_info(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct msm_fb_data_type *mfd = fbi->par;
|
||||
|
||||
if (is_split_lm(mfd) && (fbi->var.yres > fbi->var.xres)) {
|
||||
pr_debug("always split mode enabled\n");
|
||||
ret = scnprintf(buf, PAGE_SIZE,
|
||||
"src_split_always\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mdss_fb_get_thermal_level(struct device *dev,
|
||||
|
@ -588,21 +613,6 @@ static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mdss_fb_get_src_split_info(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct msm_fb_data_type *mfd = fbi->par;
|
||||
int ret = 0;
|
||||
|
||||
if ((mfd->split_mode == MDP_SPLIT_MODE_LM) &&
|
||||
(fbi->var.yres > 2048) && (fbi->var.yres > fbi->var.xres))
|
||||
ret = scnprintf(buf, PAGE_SIZE,
|
||||
"src_split_always\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
|
||||
static DEVICE_ATTR(msm_fb_split, S_IRUGO | S_IWUSR, mdss_fb_show_split,
|
||||
mdss_fb_store_split);
|
||||
|
@ -699,9 +709,11 @@ static int mdss_fb_probe(struct platform_device *pdev)
|
|||
mfd->fb_imgType = MDP_RGBA_8888;
|
||||
|
||||
mfd->pdev = pdev;
|
||||
|
||||
mfd->split_mode = MDP_SPLIT_MODE_NONE;
|
||||
if (pdata->next)
|
||||
mfd->split_mode = MDP_SPLIT_MODE_LM;
|
||||
mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY;
|
||||
|
||||
mfd->mdp = *mdp_instance;
|
||||
INIT_LIST_HEAD(&mfd->proc_list);
|
||||
|
||||
|
@ -715,6 +727,8 @@ static int mdss_fb_probe(struct platform_device *pdev)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
mdss_fb_get_split(mfd);
|
||||
|
||||
if (mfd->mdp.init_fnc) {
|
||||
rc = mfd->mdp.init_fnc(mfd);
|
||||
if (rc) {
|
||||
|
@ -1136,6 +1150,7 @@ static int mdss_fb_start_disp_thread(struct msm_fb_data_type *mfd)
|
|||
pr_debug("%pS: start display thread fb%d\n",
|
||||
__builtin_return_address(0), mfd->index);
|
||||
|
||||
/* this is needed for new split request from debugfs */
|
||||
mdss_fb_get_split(mfd);
|
||||
|
||||
atomic_set(&mfd->commits_pending, 0);
|
||||
|
|
|
@ -84,15 +84,26 @@ enum mdp_notify_event {
|
|||
/**
|
||||
* enum mdp_split_mode - Lists the possible split modes in the device
|
||||
*
|
||||
* @MDP_SPLIT_MODE_NONE: Not a Dual display, no panel split.
|
||||
* @MDP_SPLIT_MODE_LM: Dual Display is true, Split across layer mixers
|
||||
* @MDP_SPLIT_MODE_DST: Dual Display is true, Split is in the Destination
|
||||
* i.e ping pong split.
|
||||
* @MDP_SPLIT_MODE_NONE: Single physical display with single ctl path
|
||||
* and single layer mixer.
|
||||
* i.e. 1080p single DSI with single LM.
|
||||
* #MDP_DUAL_LM_SINGLE_DISPLAY: Single physical display with signle ctl
|
||||
* path but two layer mixers.
|
||||
* i.e. WQXGA eDP or 4K HDMI primary or 1080p
|
||||
* single DSI with split LM to reduce power.
|
||||
* @MDP_DUAL_LM_DUAL_DISPLAY: Two physically separate displays with two
|
||||
* separate but synchronized ctl paths. Each ctl
|
||||
* path with its own layer mixer.
|
||||
* i.e. 1440x2560 with two DSI interfaces.
|
||||
* @MDP_PINGPONG_SPLIT: Two physically separate display but single ctl path with
|
||||
* single layer mixer. Data is split at pingpong module.
|
||||
* i.e. 1440x2560 on chipsets with single DSI interface.
|
||||
*/
|
||||
enum mdp_split_mode {
|
||||
MDP_SPLIT_MODE_NONE,
|
||||
MDP_SPLIT_MODE_LM,
|
||||
MDP_SPLIT_MODE_DST,
|
||||
MDP_DUAL_LM_SINGLE_DISPLAY,
|
||||
MDP_DUAL_LM_DUAL_DISPLAY,
|
||||
MDP_PINGPONG_SPLIT,
|
||||
};
|
||||
|
||||
struct disp_info_type_suspend {
|
||||
|
@ -298,20 +309,24 @@ static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function returns true for either Layer Mixer split or Ping pong split */
|
||||
/* Function returns true for either any kind of dual display */
|
||||
static inline bool is_panel_split(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
return (mfd && (!(mfd->split_mode == MDP_SPLIT_MODE_NONE)));
|
||||
return mfd &&
|
||||
(mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY ||
|
||||
mfd->split_mode == MDP_PINGPONG_SPLIT);
|
||||
}
|
||||
/* Function returns true, if Layer Mixer split is Set */
|
||||
static inline bool is_split_lm(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
return (mfd && (mfd->split_mode == MDP_SPLIT_MODE_LM));
|
||||
return mfd &&
|
||||
(mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY ||
|
||||
mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY);
|
||||
}
|
||||
/* Function returns true, if Ping pong split is Set*/
|
||||
static inline bool is_split_dst(struct msm_fb_data_type *mfd)
|
||||
static inline bool is_pingpong_split(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
return (mfd && (mfd->split_mode == MDP_SPLIT_MODE_DST));
|
||||
return mfd && (mfd->split_mode == MDP_PINGPONG_SPLIT);
|
||||
}
|
||||
|
||||
static inline bool mdss_fb_is_power_off(struct msm_fb_data_type *mfd)
|
||||
|
|
|
@ -2731,7 +2731,7 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
|
|||
if (rc)
|
||||
pr_debug("Could not read optional property: highest bank bit\n");
|
||||
|
||||
mdata->has_dst_split = of_property_read_bool(pdev->dev.of_node,
|
||||
mdata->has_pingpong_split = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,mdss-has-dst-split");
|
||||
|
||||
/*
|
||||
|
|
|
@ -1888,7 +1888,7 @@ static inline u32 get_panel_width(struct mdss_mdp_ctl *ctl)
|
|||
u32 width;
|
||||
|
||||
width = get_panel_xres(&ctl->panel_data->panel_info);
|
||||
if (ctl->panel_data->next && is_split_dst(ctl->mfd))
|
||||
if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
|
||||
width += get_panel_xres(&ctl->panel_data->next->panel_info);
|
||||
|
||||
return width;
|
||||
|
@ -1959,8 +1959,8 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
|
|||
ctl->mixer_left->height = height;
|
||||
ctl->mixer_left->roi = (struct mdss_rect) {0, 0, width, height};
|
||||
|
||||
if (is_panel_split(ctl->mfd)) {
|
||||
pr_debug("split display detected\n");
|
||||
if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
|
||||
pr_debug("dual display detected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2423,7 +2423,7 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
|
|||
temp = readl_relaxed(ctl->mdata->mdp_base +
|
||||
MDSS_MDP_REG_DISP_INTF_SEL);
|
||||
temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
|
||||
if (is_split_dst(ctl->mfd))
|
||||
if (is_pingpong_split(ctl->mfd))
|
||||
temp |= (ctl->intf_type << (ctl->intf_num * 8));
|
||||
|
||||
writel_relaxed(temp, ctl->mdata->mdp_base +
|
||||
|
@ -2487,7 +2487,8 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
|
|||
|
||||
ret = mdss_mdp_ctl_start_sub(ctl, handoff);
|
||||
if (ret == 0) {
|
||||
if (sctl && is_split_lm(ctl->mfd)) {
|
||||
if (sctl && ctl->mfd &&
|
||||
ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
|
||||
/*split display available */
|
||||
ret = mdss_mdp_ctl_start_sub(sctl, handoff);
|
||||
if (!ret)
|
||||
|
@ -2501,7 +2502,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
|
|||
out = (mixer->height << 16) | mixer->width;
|
||||
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, out);
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
|
||||
} else if (is_split_dst(ctl->mfd)) {
|
||||
} else if (is_pingpong_split(ctl->mfd)) {
|
||||
mdss_mdp_ctl_dst_split_display_enable(1, ctl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
|
|||
|
||||
pingpong_base = mixer->pingpong_base;
|
||||
/* for dst split pp_num is cmd session (0 and 1) */
|
||||
if (is_split_dst(ctl->mfd))
|
||||
if (is_pingpong_split(ctl->mfd))
|
||||
pingpong_base += ctx->pp_num * SPLIT_MIXER_OFFSET;
|
||||
|
||||
mdss_mdp_pingpong_write(pingpong_base,
|
||||
|
@ -866,7 +866,7 @@ int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
|
|||
if (session >= MAX_SESSIONS)
|
||||
return 0;
|
||||
|
||||
if (is_split_dst(ctl->mfd)) {
|
||||
if (is_pingpong_split(ctl->mfd)) {
|
||||
ret = mdss_mdp_cmd_intfs_stop(ctl, (session + 1),
|
||||
panel_power_state);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
|
@ -1096,7 +1096,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
if (session >= MAX_SESSIONS)
|
||||
return 0;
|
||||
|
||||
if (is_split_dst(ctl->mfd)) {
|
||||
if (is_pingpong_split(ctl->mfd)) {
|
||||
ret = mdss_mdp_cmd_intfs_setup(ctl, (session + 1));
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
@ -1140,7 +1140,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
}
|
||||
|
||||
ctx->ctl = ctl;
|
||||
ctx->pp_num = (is_split_dst(ctl->mfd) ? session : mixer->num);
|
||||
ctx->pp_num = (is_pingpong_split(ctl->mfd) ? session : mixer->num);
|
||||
ctx->pp_timeout_report_cnt = 0;
|
||||
init_waitqueue_head(&ctx->pp_waitq);
|
||||
init_completion(&ctx->stop_comp);
|
||||
|
|
|
@ -425,7 +425,7 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
|
|||
if (pdata == NULL)
|
||||
return 0;
|
||||
|
||||
if (is_split_dst(ctl->mfd)) {
|
||||
if (is_pingpong_split(ctl->mfd)) {
|
||||
ret = mdss_mdp_video_intfs_stop(ctl, pdata->next, (inum + 1));
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
@ -849,7 +849,7 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
|
|||
pr_err("invalid ctx\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (is_split_dst(ctl->mfd)) {
|
||||
} else if (is_pingpong_split(ctl->mfd)) {
|
||||
/*
|
||||
* On targets when destination split is enabled, mixer swap
|
||||
* is not valid. So we can safely assume that ctl->intf_num
|
||||
|
@ -1080,7 +1080,7 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
|
|||
pdata->panel_info.cont_splash_enabled = 0;
|
||||
if (sctl)
|
||||
sctl->panel_data->panel_info.cont_splash_enabled = 0;
|
||||
else if (ctl->panel_data->next && is_split_dst(ctl->mfd))
|
||||
else if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
|
||||
ctl->panel_data->next->panel_info.cont_splash_enabled = 0;
|
||||
|
||||
if (!handoff) {
|
||||
|
@ -1229,7 +1229,7 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
if (pdata == NULL)
|
||||
return 0;
|
||||
|
||||
if (is_split_dst(ctl->mfd)) {
|
||||
if (is_pingpong_split(ctl->mfd)) {
|
||||
ret = mdss_mdp_video_intfs_setup(ctl, pdata->next, (inum + 1));
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
|
|
@ -3551,7 +3551,7 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
|
|||
INIT_WORK(&ctl->remove_underrun_handler,
|
||||
remove_underrun_vsync_handler);
|
||||
|
||||
if (is_split_lm(mfd)) {
|
||||
if (mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
|
||||
/* enable split display */
|
||||
rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next);
|
||||
if (rc) {
|
||||
|
@ -3840,7 +3840,7 @@ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (is_split_lm(mfd)) {
|
||||
if (mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
if (!sctl) {
|
||||
pr_err("cannot get secondary ctl. fail the handoff\n");
|
||||
|
@ -4058,8 +4058,8 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
|
|||
}
|
||||
mfd->mdp.private1 = mdp5_data;
|
||||
mfd->wait_for_kickoff = true;
|
||||
if (is_panel_split(mfd) && mdp5_data->mdata->has_dst_split)
|
||||
mfd->split_mode = MDP_SPLIT_MODE_DST;
|
||||
if (is_panel_split(mfd) && mdp5_data->mdata->has_pingpong_split)
|
||||
mfd->split_mode = MDP_PINGPONG_SPLIT;
|
||||
|
||||
if (mfd->panel_info->partial_update_enabled && is_split_lm(mfd))
|
||||
mdp5_data->mdata->has_src_split = false;
|
||||
|
@ -4084,7 +4084,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
|
|||
mfd->panel_orientation = mfd->panel_info->panel_orientation;
|
||||
|
||||
if ((mfd->panel_info->panel_orientation & MDP_FLIP_LR) &&
|
||||
(is_split_lm(mfd)))
|
||||
(mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY))
|
||||
mdp5_data->mixer_swap = true;
|
||||
|
||||
rc = sysfs_create_group(&dev->kobj, &mdp_overlay_sysfs_group);
|
||||
|
|
Loading…
Add table
Reference in a new issue