Loading Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +31 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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]; Loading drivers/video/fbdev/msm/mdss_dsi_panel.c +44 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +71 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -144,26 +145,20 @@ 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, MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff; 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; Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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; Loading drivers/video/fbdev/msm/mdss_panel.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +31 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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]; Loading
drivers/video/fbdev/msm/mdss_dsi_panel.c +44 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading
drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +71 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -144,26 +145,20 @@ 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, MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff; 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; Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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; Loading
drivers/video/fbdev/msm/mdss_panel.h +4 −0 Original line number Diff line number Diff line Loading @@ -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