summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt3
-rw-r--r--drivers/video/fbdev/msm/mdss.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c11
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h12
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_hwio.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c102
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c71
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.c1
-rw-r--r--include/uapi/linux/msm_mdp_ext.h9
12 files changed, 236 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 9fc942cc627d..90abf0305319 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -152,7 +152,8 @@ Optional properties:
"dfps_immediate_porch_mode_vfp" = FPS change request is
implemented immediately by changing panel vertical
front porch values.
-- qcom,min-refresh-rate: Minimum refresh rate supported by the panel.
+- qcom,min-refresh-rate: Minimum refresh rate supported by the panel. Used in
+ adaptive variable refresh(AVR) to compute new avr vtotal
- qcom,max-refresh-rate: Maximum refresh rate supported by the panel. If max refresh
rate is not specified, then the frame rate of the panel in
qcom,mdss-dsi-panel-framerate is used.
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 88950e9cb2aa..b601cafba6fd 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -176,6 +176,7 @@ enum mdss_hw_capabilities {
MDSS_CAPS_10_BIT_SUPPORTED,
MDSS_CAPS_CWB_SUPPORTED,
MDSS_CAPS_MDP_VOTE_CLK_NOT_SUPPORTED,
+ MDSS_CAPS_AVR_SUPPORTED,
MDSS_CAPS_MAX,
};
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 9548ea471385..2e54f335e948 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -1967,7 +1967,6 @@ static void mdss_dsi_parse_dfps_config(struct device_node *pan_node,
pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE;
pr_debug("default dfps mode: suspend/resume\n");
}
- mdss_dsi_set_refresh_rate_range(pan_node, pinfo);
} else {
pinfo->dynamic_fps = false;
pr_debug("dfps update mode not configured: disable\n");
@@ -2528,6 +2527,8 @@ static int mdss_panel_parse_dt(struct device_node *np,
mdss_dsi_parse_dfps_config(np, ctrl_pdata);
+ mdss_dsi_set_refresh_rate_range(np, pinfo);
+
pinfo->is_dba_panel = of_property_read_bool(np,
"qcom,dba-panel");
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index cc8ce49c7387..99a924c38d65 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -552,13 +552,19 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
struct msm_fb_data_type *mfd = fbi->par;
struct mdss_panel_info *pinfo = mfd->panel_info;
int ret;
+ bool dfps_porch_mode = false;
+
+ if (pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP ||
+ pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP)
+ dfps_porch_mode = true;
ret = scnprintf(buf, PAGE_SIZE,
"pu_en=%d\nxstart=%d\nwalign=%d\nystart=%d\nhalign=%d\n"
"min_w=%d\nmin_h=%d\nroi_merge=%d\ndyn_fps_en=%d\n"
"min_fps=%d\nmax_fps=%d\npanel_name=%s\n"
"primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n"
- "is_cec_supported=%d\nis_pingpong_split=%d\n",
+ "is_cec_supported=%d\nis_pingpong_split=%d\n"
+ "dfps_porch_mode=%d\n",
pinfo->partial_update_enabled,
pinfo->roi_alignment.xstart_pix_align,
pinfo->roi_alignment.width_pix_align,
@@ -570,7 +576,8 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
pinfo->dynamic_fps, pinfo->min_fps, pinfo->max_fps,
pinfo->panel_name, pinfo->is_prim_panel,
pinfo->is_pluggable, pinfo->display_id,
- pinfo->is_cec_supported, is_pingpong_split(mfd));
+ pinfo->is_cec_supported, is_pingpong_split(mfd),
+ dfps_porch_mode);
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 5a355f226179..518b84fbad51 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1950,6 +1950,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
+ set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
break;
default:
mdata->max_target_zorder = 4; /* excluding base layer */
@@ -2489,6 +2490,8 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev,
SPRINT(" separate_rotator");
if (test_bit(MDSS_CAPS_CWB_SUPPORTED, mdata->mdss_caps_map))
SPRINT(" concurrent_writeback");
+ if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map))
+ SPRINT(" avr");
SPRINT("\n");
#undef SPRINT
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index da5e7bb8a343..da60570c7085 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -303,6 +303,11 @@ enum mdp_wb_blk_caps {
MDSS_MDP_WB_UBWC = BIT(3),
};
+enum mdss_mdp_avr_mode {
+ MDSS_MDP_AVR_CONTINUOUS = 0,
+ MDSS_MDP_AVR_ONE_SHOT,
+};
+
/**
* enum perf_calc_vote_mode - enum to decide if mdss_mdp_get_bw_vote_mode
* function needs an extra efficiency factor.
@@ -391,6 +396,7 @@ struct mdss_mdp_ctl_intfs_ops {
/* to update lineptr, [1..yres] - enable, 0 - disable */
int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable);
+ int (*avr_ctrl_fnc)(struct mdss_mdp_ctl *);
};
struct mdss_mdp_cwb {
@@ -406,6 +412,11 @@ struct mdss_mdp_cwb {
struct work_struct cwb_work;
};
+struct mdss_mdp_avr_info {
+ bool avr_enabled;
+ int avr_mode;
+};
+
struct mdss_mdp_ctl {
u32 num;
char __iomem *base;
@@ -513,6 +524,7 @@ struct mdss_mdp_ctl {
/* dynamic resolution switch during cont-splash handoff */
bool switch_with_handoff;
+ struct mdss_mdp_avr_info avr_info;
};
struct mdss_mdp_mixer {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 3fc6d94393d5..1a0ba8f0e2a7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -5528,6 +5528,26 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
sctl = mdss_mdp_get_split_ctl(ctl);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ if (ctl->ops.avr_ctrl_fnc) {
+ ret = ctl->ops.avr_ctrl_fnc(ctl);
+ if (ret) {
+ pr_err("error configuring avr ctrl registers ctl=%d err=%d\n",
+ ctl->num, ret);
+ mutex_unlock(&ctl->lock);
+ return ret;
+ }
+ }
+
+ if (sctl && sctl->ops.avr_ctrl_fnc) {
+ ret = sctl->ops.avr_ctrl_fnc(sctl);
+ if (ret) {
+ pr_err("error configuring avr ctrl registers sctl=%d err=%d\n",
+ sctl->num, ret);
+ mutex_unlock(&ctl->lock);
+ return ret;
+ }
+ }
+
mutex_lock(&ctl->flush_lock);
/*
diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
index 74ab902f6e8e..de868bcd8f6f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
@@ -688,6 +688,11 @@ enum mdss_mpd_intf_index {
#define MDSS_MDP_REG_INTF_PROG_LINE_INTR_CONF 0x250
#define MDSS_MDP_REG_INTF_VBLANK_END_CONF 0x264
+#define MDSS_MDP_REG_INTF_AVR_CONTROL 0x270
+#define MDSS_MDP_REG_INTF_AVR_MODE 0x274
+#define MDSS_MDP_REG_INTF_AVR_TRIGGER 0x278
+#define MDSS_MDP_REG_INTF_AVR_VTOTAL 0x27C
+
#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index d1ced303b059..ee14fd0d0660 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -403,6 +403,76 @@ static void mdss_mdp_video_intf_recovery(void *data, int event)
}
}
+static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl,
+ struct intf_timing_params *p,
+ struct mdss_mdp_video_ctx *ctx)
+{
+ struct mdss_data_type *mdata = ctl->mdata;
+
+ if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map)) {
+ struct mdss_panel_data *pdata = ctl->panel_data;
+ u32 hsync_period = p->hsync_pulse_width + p->h_back_porch +
+ p->width + p->h_front_porch;
+ u32 vsync_period = p->vsync_pulse_width + p->v_back_porch +
+ p->height + p->v_front_porch;
+ u32 min_fps = pdata->panel_info.min_fps;
+ u32 diff_fps = abs(pdata->panel_info.default_fps - min_fps);
+ u32 vtotal = mdss_panel_get_vtotal(&pdata->panel_info);
+
+ int add_porches = mult_frac(vtotal, diff_fps, min_fps);
+
+ u32 vsync_period_slow = vsync_period + add_porches;
+ u32 avr_vtotal = vsync_period_slow * hsync_period;
+
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_VTOTAL, avr_vtotal);
+
+ MDSS_XLOG(min_fps, vsync_period, vsync_period_slow, avr_vtotal);
+ }
+}
+
+static int mdss_mdp_video_avr_trigger_setup(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = NULL;
+ struct mdss_data_type *mdata = ctl->mdata;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
+ if (!ctx || !ctx->ref_cnt) {
+ pr_err("invalid master ctx\n");
+ return -EINVAL;
+ }
+
+ if (!ctl->is_master)
+ return 0;
+
+ if (ctl->avr_info.avr_enabled &&
+ test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map))
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_TRIGGER, 1);
+
+ return 0;
+}
+
+static void mdss_mdp_video_avr_ctrl_setup(struct mdss_mdp_video_ctx *ctx,
+ struct mdss_mdp_avr_info *avr_info, bool is_master)
+{
+ u32 avr_ctrl = 0;
+ u32 avr_mode = 0;
+
+ avr_ctrl = avr_info->avr_enabled;
+ avr_mode = avr_info->avr_mode;
+
+ /* Enable avr_vsync_clear_en bit to clear avr in next vsync */
+ if (avr_mode == MDSS_MDP_AVR_ONE_SHOT)
+ avr_mode |= (1 << 8);
+
+ if (is_master)
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_CONTROL, avr_ctrl);
+
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_MODE, avr_mode);
+
+ pr_debug("intf:%d avr_mode:%x avr_ctrl:%x\n",
+ ctx->intf_num, avr_mode, avr_ctrl);
+}
+
static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
struct intf_timing_params *p,
struct mdss_mdp_video_ctx *ctx)
@@ -1530,6 +1600,12 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
CTL_INTF_EVENT_FLAG_DEFAULT);
}
+ rc = mdss_mdp_video_avr_trigger_setup(ctl);
+ if (rc) {
+ pr_err("avr trigger setup failed\n");
+ return rc;
+ }
+
if (mdss_mdp_is_lineptr_supported(ctl))
mdss_mdp_video_lineptr_ctrl(ctl, true);
@@ -1886,6 +1962,8 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
mdss_mdp_handoff_programmable_fetch(ctl, ctx);
}
+ mdss_mdp_video_avr_vtotal_setup(ctl, itp, ctx);
+
mdss_mdp_disable_prefill(ctl);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_PANEL_FORMAT, ctl->dst_format);
@@ -2124,6 +2202,29 @@ static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl)
return 0;
}
+static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = NULL, *sctx = NULL;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
+ if (!ctx || !ctx->ref_cnt) {
+ pr_err("invalid master ctx\n");
+ return -EINVAL;
+ }
+ mdss_mdp_video_avr_ctrl_setup(ctx, &ctl->avr_info, ctl->is_master);
+
+ if (is_pingpong_split(ctl->mfd)) {
+ sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX];
+ if (!sctx || !sctx->ref_cnt) {
+ pr_err("invalid slave ctx\n");
+ return -EINVAL;
+ }
+ mdss_mdp_video_avr_ctrl_setup(sctx, &ctl->avr_info, false);
+ }
+
+ return 0;
+}
+
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
{
int intfs_num, ret = 0;
@@ -2144,6 +2245,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
ctl->ops.config_fps_fnc = mdss_mdp_video_config_fps;
ctl->ops.early_wake_up_fnc = mdss_mdp_video_early_wake_up;
ctl->ops.update_lineptr = mdss_mdp_video_lineptr_ctrl;
+ ctl->ops.avr_ctrl_fnc = mdss_mdp_video_avr_ctrl;
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 0ae420724d61..35bd0932f321 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -288,6 +288,57 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
return ret;
}
+static int mdss_mdp_avr_validate(struct msm_fb_data_type *mfd,
+ struct mdp_layer_commit_v1 *commit)
+{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ int req = 0;
+ struct mdss_panel_info *pinfo = NULL;
+
+ if (!ctl || !mdata || !commit) {
+ pr_err("Invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ if (!(commit->flags & MDP_COMMIT_AVR_EN))
+ return 0;
+
+ pinfo = &ctl->panel_data->panel_info;
+
+ if (!test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map) ||
+ (pinfo->max_fps == pinfo->min_fps)) {
+ pr_err("AVR not supported\n");
+ return -ENODEV;
+ }
+
+ if (pinfo->dynamic_fps &&
+ !(pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP ||
+ pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP)) {
+ pr_err("Dynamic fps and AVR cannot coexists\n");
+ return -EINVAL;
+ }
+
+ if (!ctl->is_video_mode) {
+ pr_err("AVR not supported in command mode\n");
+ return -EINVAL;
+ }
+
+ return req;
+}
+
+static void __update_avr_info(struct mdss_mdp_ctl *ctl,
+ struct mdp_layer_commit_v1 *commit)
+{
+ if (commit->flags & MDP_COMMIT_AVR_EN)
+ ctl->avr_info.avr_enabled = true;
+
+ ctl->avr_info.avr_mode = MDSS_MDP_AVR_CONTINUOUS;
+
+ if (commit->flags & MDP_COMMIT_AVR_ONE_SHOT_MODE)
+ ctl->avr_info.avr_mode = MDSS_MDP_AVR_ONE_SHOT;
+}
+
/*
* __layer_needs_src_split() - check needs source split configuration
* @layer: input layer
@@ -2247,13 +2298,13 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd,
struct mdss_overlay_private *mdp5_data;
struct mdss_mdp_data *src_data[MDSS_MDP_MAX_SSPP];
struct mdss_mdp_validate_info_t *validate_info_list;
+ struct mdss_mdp_ctl *sctl = NULL;
mdp5_data = mfd_to_mdp5_data(mfd);
if (!mdp5_data || !mdp5_data->ctl)
return -EINVAL;
-
if (commit->output_layer) {
ret = __is_cwb_requested(commit->output_layer->flags);
if (IS_ERR_VALUE(ret)) {
@@ -2267,6 +2318,18 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd,
}
}
+ ret = mdss_mdp_avr_validate(mfd, commit);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("AVR validate failed\n");
+ return -EINVAL;
+ }
+
+ __update_avr_info(mdp5_data->ctl, commit);
+
+ sctl = mdss_mdp_get_split_ctl(mdp5_data->ctl);
+ if (sctl)
+ __update_avr_info(sctl, commit);
+
layer_list = commit->input_layers;
/* handle null commit */
@@ -2428,6 +2491,12 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
}
}
+ rc = mdss_mdp_avr_validate(mfd, commit);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("AVR validate failed\n");
+ return -EINVAL;
+ }
+
return __validate_layers(mfd, file, commit);
}
diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c
index 97025b3a9c23..61911810b2c0 100644
--- a/drivers/video/fbdev/msm/mdss_panel.c
+++ b/drivers/video/fbdev/msm/mdss_panel.c
@@ -644,6 +644,7 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt,
pinfo->dsc_enc_total = pt->dsc_enc_total;
pinfo->fbc = pt->fbc;
pinfo->compression_mode = pt->compression_mode;
+ pinfo->default_fps = pinfo->mipi.frame_rate;
pinfo->roi_alignment = pt->roi_alignment;
pinfo->te = pt->te;
diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h
index 8472224f33a6..811d8b4e1994 100644
--- a/include/uapi/linux/msm_mdp_ext.h
+++ b/include/uapi/linux/msm_mdp_ext.h
@@ -138,6 +138,15 @@ VALIDATE/COMMIT FLAG CONFIGURATION
*/
#define MDP_COMMIT_SYNC_FENCE_WAIT 0x04
+/* Flag to enable AVR(Adaptive variable refresh) feature. */
+#define MDP_COMMIT_AVR_EN 0x08
+
+/*
+ * Flag to select one shot mode when AVR feature is enabled.
+ * Default mode is continuous mode.
+ */
+#define MDP_COMMIT_AVR_ONE_SHOT_MODE 0x10
+
/* Flag to enable concurrent writeback for the frame */
#define MDP_COMMIT_CWB_EN 0x800