Merge "msm: mdss: add mdp guard window property"
This commit is contained in:
commit
d0a8d1d591
4 changed files with 150 additions and 13 deletions
|
@ -249,6 +249,35 @@ Optional properties:
|
|||
60 = 60 frames per second (default)
|
||||
- qcom,mdss-dsi-panel-clockrate: A 64 bit value specifies the panel clock speed in Hz.
|
||||
0 = default value.
|
||||
- qcom,mdss-mdp-kickoff-threshold: This property can be used to define a region
|
||||
(in terms of scanlines) where the
|
||||
hardware is allowed
|
||||
to trigger a data transfer from MDP to DSI.
|
||||
If this property is used, the region must be defined setting
|
||||
two values, the low and the high thresholds:
|
||||
<low_threshold high_threshold>
|
||||
Where following condition must be met:
|
||||
low_threshold < high_threshold
|
||||
These values will be used by the driver in such way that if
|
||||
the Driver receives a request to kickoff a transfer (MDP to DSI),
|
||||
the transfer will be triggered only if the following condition
|
||||
is satisfied:
|
||||
low_threshold < scanline < high_threshold
|
||||
If the condition is not met, then the driver will delay the
|
||||
transfer by the time defined in the following property:
|
||||
"qcom,mdss-mdp-kickoff-delay".
|
||||
So in order to use this property, the delay property must
|
||||
be defined as well and greater than 0.
|
||||
- qcom,mdss-mdp-kickoff-delay: This property defines the delay in microseconds that
|
||||
the driver will delay before triggering an MDP transfer if the
|
||||
thresholds defined by the following property are not met:
|
||||
"qcom,mdss-mdp-kickoff-threshold".
|
||||
So in order to use this property, the threshold property must
|
||||
be defined as well. Note that this delay cannot be zero
|
||||
and also should not be greater than
|
||||
the fps window.
|
||||
i.e. For 60fps value should not exceed
|
||||
16666 uS.
|
||||
- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode
|
||||
panels in microseconds. Driver uses this number to adjust
|
||||
the clock rate according to the expected transfer time.
|
||||
|
@ -568,6 +597,8 @@ Example:
|
|||
qcom,mdss-dsi-dma-trigger = <0>;
|
||||
qcom,mdss-dsi-panel-framerate = <60>;
|
||||
qcom,mdss-dsi-panel-clockrate = <424000000>;
|
||||
qcom,mdss-mdp-kickoff-threshold = <11 2430>;
|
||||
qcom,mdss-mdp-kickoff-delay = <1000>;
|
||||
qcom,mdss-mdp-transfer-time-us = <12500>;
|
||||
qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
|
||||
22 27 1e 03 04 00];
|
||||
|
|
|
@ -856,6 +856,48 @@ static int mdss_dsi_panel_low_power_config(struct mdss_panel_data *pdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mdss_dsi_parse_mdp_kickoff_threshold(struct device_node *np,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
int len, rc;
|
||||
const u32 *src;
|
||||
u32 tmp;
|
||||
u32 max_delay_us;
|
||||
|
||||
pinfo->mdp_koff_thshold = false;
|
||||
src = of_get_property(np, "qcom,mdss-mdp-kickoff-threshold", &len);
|
||||
if (!src || (len == 0))
|
||||
return;
|
||||
|
||||
rc = of_property_read_u32(np, "qcom,mdss-mdp-kickoff-delay", &tmp);
|
||||
if (!rc)
|
||||
pinfo->mdp_koff_delay = tmp;
|
||||
else
|
||||
return;
|
||||
|
||||
if (pinfo->mipi.frame_rate == 0) {
|
||||
pr_err("cannot enable guard window, unexpected panel fps\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pinfo->mdp_koff_thshold_low = be32_to_cpu(src[0]);
|
||||
pinfo->mdp_koff_thshold_high = be32_to_cpu(src[1]);
|
||||
max_delay_us = 1000000 / pinfo->mipi.frame_rate;
|
||||
|
||||
/* enable the feature if threshold is valid */
|
||||
if ((pinfo->mdp_koff_thshold_low < pinfo->mdp_koff_thshold_high) &&
|
||||
((pinfo->mdp_koff_delay > 0) ||
|
||||
(pinfo->mdp_koff_delay < max_delay_us)))
|
||||
pinfo->mdp_koff_thshold = true;
|
||||
|
||||
pr_debug("panel kickoff thshold:[%d, %d] delay:%d (max:%d) enable:%d\n",
|
||||
pinfo->mdp_koff_thshold_low,
|
||||
pinfo->mdp_koff_thshold_high,
|
||||
pinfo->mdp_koff_delay,
|
||||
max_delay_us,
|
||||
pinfo->mdp_koff_thshold);
|
||||
}
|
||||
|
||||
static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger,
|
||||
char *trigger_key)
|
||||
{
|
||||
|
@ -2497,6 +2539,8 @@ static int mdss_panel_parse_dt(struct device_node *np,
|
|||
rc = of_property_read_u32(np, "qcom,mdss-mdp-transfer-time-us", &tmp);
|
||||
pinfo->mdp_transfer_time_us = (!rc ? tmp : DEFAULT_MDP_TRANSFER_TIME);
|
||||
|
||||
mdss_dsi_parse_mdp_kickoff_threshold(np, pinfo);
|
||||
|
||||
pinfo->mipi.lp11_init = of_property_read_bool(np,
|
||||
"qcom,mdss-dsi-lp11-init");
|
||||
rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp);
|
||||
|
|
|
@ -73,6 +73,7 @@ struct mdss_mdp_cmd_ctx {
|
|||
struct mutex clk_mtx;
|
||||
spinlock_t clk_lock;
|
||||
spinlock_t koff_lock;
|
||||
spinlock_t ctlstart_lock;
|
||||
struct work_struct gate_clk_work;
|
||||
struct delayed_work delayed_off_clk_work;
|
||||
struct work_struct pp_done_work;
|
||||
|
@ -144,15 +145,11 @@ static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
|
|||
u32 init;
|
||||
u32 height;
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
|
||||
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
|
||||
if (!mixer) {
|
||||
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
|
||||
if (!mixer) {
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
if (!mixer)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
init = mdss_mdp_pingpong_read(mixer->pingpong_base,
|
||||
|
@ -160,10 +157,8 @@ static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
|
|||
height = mdss_mdp_pingpong_read(mixer->pingpong_base,
|
||||
MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT) & 0xffff;
|
||||
|
||||
if (height < init) {
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
if (height < init)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cnt = mdss_mdp_pingpong_read(mixer->pingpong_base,
|
||||
MDSS_MDP_REG_PP_INT_COUNT_VAL) & 0xffff;
|
||||
|
@ -173,13 +168,21 @@ static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
|
|||
else
|
||||
cnt -= init;
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
|
||||
pr_debug("cnt=%d init=%d height=%d\n", cnt, init, height);
|
||||
exit:
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static inline u32 mdss_mdp_cmd_line_count_wrapper(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
ret = mdss_mdp_cmd_line_count(ctl);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_mdp_tearcheck_enable(struct mdss_mdp_ctl *ctl, bool enable)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
@ -2677,12 +2680,42 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool wait_for_read_ptr_if_late(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_ctl *sctl, struct mdss_panel_info *pinfo)
|
||||
{
|
||||
u32 line_count;
|
||||
u32 sline_count = 0;
|
||||
bool ret = true;
|
||||
u32 low_threshold = pinfo->mdp_koff_thshold_low;
|
||||
u32 high_threshold = pinfo->mdp_koff_thshold_high;
|
||||
|
||||
/* read the line count */
|
||||
line_count = mdss_mdp_cmd_line_count(ctl);
|
||||
if (sctl)
|
||||
sline_count = mdss_mdp_cmd_line_count(sctl);
|
||||
|
||||
/* if line count is between the range, return to trigger transfer */
|
||||
if (((line_count > low_threshold) && (line_count < high_threshold)) &&
|
||||
(!sctl || ((sline_count > low_threshold) &&
|
||||
(sline_count < high_threshold))))
|
||||
ret = false;
|
||||
|
||||
pr_debug("threshold:[%d, %d]\n", low_threshold, high_threshold);
|
||||
pr_debug("line:%d sline:%d ret:%d\n", line_count, sline_count, ret);
|
||||
MDSS_XLOG(line_count, sline_count, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_cmd_ctx *ctx)
|
||||
struct mdss_mdp_ctl *sctl, struct mdss_mdp_cmd_ctx *ctx)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
bool is_pp_split = is_pingpong_split(ctl->mfd);
|
||||
struct mdss_panel_info *pinfo = NULL;
|
||||
|
||||
if (ctl->panel_data)
|
||||
pinfo = &ctl->panel_data->panel_info;
|
||||
|
||||
MDSS_XLOG(ctx->autorefresh_state);
|
||||
|
||||
|
@ -2707,9 +2740,33 @@ static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl,
|
|||
ctx->autorefresh_state = MDP_AUTOREFRESH_ON;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Some panels can require that mdp is within some range
|
||||
* of the scanlines in order to trigger the tansfer.
|
||||
* If that is the case, make sure the panel scanline
|
||||
* is within the limit to start.
|
||||
* Acquire an spinlock for this operation to raise the
|
||||
* priority of this thread and make sure the context
|
||||
* is maintained, so we can have the less time possible
|
||||
* between the check of the scanline and the kickoff.
|
||||
*/
|
||||
if (pinfo && pinfo->mdp_koff_thshold) {
|
||||
spin_lock(&ctx->ctlstart_lock);
|
||||
if (wait_for_read_ptr_if_late(ctl, sctl, pinfo)) {
|
||||
spin_unlock(&ctx->ctlstart_lock);
|
||||
usleep_range(pinfo->mdp_koff_delay,
|
||||
pinfo->mdp_koff_delay + 10);
|
||||
spin_lock(&ctx->ctlstart_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* SW Kickoff */
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
|
||||
MDSS_XLOG(0x11, ctx->autorefresh_state);
|
||||
|
||||
if (pinfo && pinfo->mdp_koff_thshold)
|
||||
spin_unlock(&ctx->ctlstart_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2841,7 +2898,7 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
}
|
||||
|
||||
/* Kickoff */
|
||||
__mdss_mdp_kickoff(ctl, ctx);
|
||||
__mdss_mdp_kickoff(ctl, sctl, ctx);
|
||||
|
||||
mdss_mdp_cmd_post_programming(ctl);
|
||||
|
||||
|
@ -3267,6 +3324,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
|
|||
init_completion(&ctx->autorefresh_done);
|
||||
spin_lock_init(&ctx->clk_lock);
|
||||
spin_lock_init(&ctx->koff_lock);
|
||||
spin_lock_init(&ctx->ctlstart_lock);
|
||||
mutex_init(&ctx->clk_mtx);
|
||||
mutex_init(&ctx->mdp_rdptr_lock);
|
||||
mutex_init(&ctx->mdp_wrptr_lock);
|
||||
|
@ -3557,7 +3615,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
|
|||
ctl->ops.wait_pingpong = mdss_mdp_cmd_wait4pingpong;
|
||||
ctl->ops.add_vsync_handler = mdss_mdp_cmd_add_vsync_handler;
|
||||
ctl->ops.remove_vsync_handler = mdss_mdp_cmd_remove_vsync_handler;
|
||||
ctl->ops.read_line_cnt_fnc = mdss_mdp_cmd_line_count;
|
||||
ctl->ops.read_line_cnt_fnc = mdss_mdp_cmd_line_count_wrapper;
|
||||
ctl->ops.restore_fnc = mdss_mdp_cmd_restore;
|
||||
ctl->ops.early_wake_up_fnc = mdss_mdp_cmd_early_wake_up;
|
||||
ctl->ops.reconfigure = mdss_mdp_cmd_reconfigure;
|
||||
|
|
|
@ -635,6 +635,10 @@ struct mdss_panel_info {
|
|||
u32 saved_fporch;
|
||||
/* current fps, once is programmed in hw */
|
||||
int current_fps;
|
||||
u32 mdp_koff_thshold_low;
|
||||
u32 mdp_koff_thshold_high;
|
||||
bool mdp_koff_thshold;
|
||||
u32 mdp_koff_delay;
|
||||
|
||||
int panel_max_fps;
|
||||
int panel_max_vtotal;
|
||||
|
|
Loading…
Add table
Reference in a new issue