diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt index ddbe584e84af..8e840c10b7a5 100644 --- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt +++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt @@ -427,8 +427,20 @@ Fudge Factors: Fudge factors are used to boost demand for applied in scenarios where panel interface can be more tolerant to memory latency such as command mode panels. -- qcom,max-bandwidth-per-pipe-kbps: This value indicates the max bandwidth in KB - that a single pipe can support without underflow. +- qcom,max-bandwidth-per-pipe-kbps: A two dimensional array indicating the max + bandwidth in KB that a single pipe can support + without underflow for various usecases. The + first parameter indicates the usecase and the + second parameter gives the max bw allowed for + the usecase. Following are the enum values for + modes in different cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. - qcom,max-bw-settings: This two dimension array indicates the max bandwidth in KB that has to be supported when particular scenarios are involved such as camera, flip. @@ -612,6 +624,8 @@ Example: qcom,max-bandwidth-low-kbps = <2300000>; qcom,max-bandwidth-high-kbps = <3000000>; + qcom,max-bandwidth-per-pipe-kbps = <4 2100000>, + <8 1800000>; qcom,max-bw-settings = <1 2300000>, <2 1700000>, <4 2300000>, diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 4c2aa01e76e7..e994cd0e7179 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -433,6 +433,10 @@ struct mdss_data_type { u32 bw_mode_bitmap; u32 max_bw_settings_cnt; + struct mdss_max_bw_settings *max_per_pipe_bw_settings; + u32 mdss_per_pipe_bw_cnt; + u32 min_bw_per_pipe; + u32 bcolor0; u32 bcolor1; u32 bcolor2; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index d8d518be0776..b4cfc8e80e3b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -2995,6 +2995,63 @@ static void mdss_mdp_parse_max_bandwidth(struct platform_device *pdev) mdata->max_bw_settings_cnt = max_bw_settings_cnt; } +static void mdss_mdp_parse_per_pipe_bandwidth(struct platform_device *pdev) +{ + + struct mdss_data_type *mdata = platform_get_drvdata(pdev); + struct mdss_max_bw_settings *max_bw_per_pipe_settings; + int max_bw_settings_cnt = 0; + const u32 *max_bw_settings; + u32 max_bw, min_bw, threshold, i = 0; + + max_bw_settings = of_get_property(pdev->dev.of_node, + "qcom,max-bandwidth-per-pipe-kbps", + &max_bw_settings_cnt); + + if (!max_bw_settings || !max_bw_settings_cnt) { + pr_debug("MDSS per pipe max bandwidth settings not found\n"); + return; + } + + /* Support targets where a common per pipe max bw is provided */ + if ((max_bw_settings_cnt / sizeof(u32)) == 1) { + mdata->max_bw_per_pipe = be32_to_cpu(max_bw_settings[0]); + mdata->max_per_pipe_bw_settings = NULL; + pr_debug("Common per pipe max bandwidth provided\n"); + return; + } + + max_bw_settings_cnt /= 2 * sizeof(u32); + + max_bw_per_pipe_settings = devm_kzalloc(&pdev->dev, + sizeof(struct mdss_max_bw_settings) * max_bw_settings_cnt, + GFP_KERNEL); + if (!max_bw_per_pipe_settings) { + pr_err("Memory allocation failed for max_bw_settings\n"); + return; + } + + mdss_mdp_parse_max_bw_array(max_bw_settings, max_bw_per_pipe_settings, + max_bw_settings_cnt); + mdata->max_per_pipe_bw_settings = max_bw_per_pipe_settings; + mdata->mdss_per_pipe_bw_cnt = max_bw_settings_cnt; + + /* Calculate min and max allowed per pipe BW */ + min_bw = mdata->max_bw_high; + max_bw = 0; + + while (i < max_bw_settings_cnt) { + threshold = mdata->max_per_pipe_bw_settings[i].mdss_max_bw_val; + if (threshold > max_bw) + max_bw = threshold; + if (threshold < min_bw) + min_bw = threshold; + ++i; + } + mdata->max_bw_per_pipe = max_bw; + mdata->min_bw_per_pipe = min_bw; +} + static int mdss_mdp_parse_dt_misc(struct platform_device *pdev) { struct mdss_data_type *mdata = platform_get_drvdata(pdev); @@ -3123,11 +3180,7 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev) if (rc) pr_debug("max bandwidth (high) property not specified\n"); - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,max-bandwidth-per-pipe-kbps", &mdata->max_bw_per_pipe); - if (rc) - pr_debug("max bandwidth (per pipe) property not specified\n"); - + mdss_mdp_parse_per_pipe_bandwidth(pdev); mdss_mdp_parse_max_bandwidth(pdev); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index d356a6d42993..00c360b6a0c2 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -1402,6 +1402,61 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, return 0; } +static u32 mdss_mdp_get_bw_by_mode(struct mdss_max_bw_settings *settings, + int count, int key) +{ + u32 value = 0, i = 0; + + while (i < count) { + if (settings[i].mdss_max_bw_mode == key) { + value = settings[i].mdss_max_bw_val; + break; + } + ++i; + } + return value; +} + +static u32 mdss_mdp_get_max_pipe_bw(struct mdss_mdp_pipe *pipe) +{ + + struct mdss_data_type *mdata = pipe->mixer_left->ctl->mdata; + struct mdss_mdp_ctl *ctl = pipe->mixer_left->ctl; + u32 flags = 0, threshold = 0, panel_orientation; + + panel_orientation = ctl->mfd->panel_orientation; + + /* Check for panel orienatation */ + panel_orientation = ctl->mfd->panel_orientation; + if (panel_orientation & MDP_FLIP_LR) + flags |= MDSS_MAX_BW_LIMIT_HFLIP; + if (panel_orientation & MDP_FLIP_UD) + flags |= MDSS_MAX_BW_LIMIT_VFLIP; + + /* check for Hflip/Vflip in pipe */ + if (pipe->flags & MDP_FLIP_LR) + flags |= MDSS_MAX_BW_LIMIT_HFLIP; + if (pipe->flags & MDP_FLIP_UD) + flags |= MDSS_MAX_BW_LIMIT_VFLIP; + + if ((flags & MDSS_MAX_BW_LIMIT_HFLIP) && + (flags & MDSS_MAX_BW_LIMIT_VFLIP)) { + threshold = mdata->min_bw_per_pipe; + } else if (flags & MDSS_MAX_BW_LIMIT_HFLIP) { + threshold = mdss_mdp_get_bw_by_mode( + mdata->max_per_pipe_bw_settings, + mdata->mdss_per_pipe_bw_cnt, + MDSS_MAX_BW_LIMIT_HFLIP); + } else if (flags & MDSS_MAX_BW_LIMIT_VFLIP) { + threshold = mdss_mdp_get_bw_by_mode( + mdata->max_per_pipe_bw_settings, + mdata->mdss_per_pipe_bw_cnt, + MDSS_MAX_BW_LIMIT_VFLIP); + } + + return threshold ? threshold : mdata->max_bw_per_pipe; +} + int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf, struct mdss_mdp_pipe *pipe) { @@ -1427,7 +1482,12 @@ int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf, /* convert bandwidth to kb */ pipe_bw = DIV_ROUND_UP_ULL(pipe_bw, 1000); - threshold = mdata->max_bw_per_pipe; + + if (!mdata->max_per_pipe_bw_settings) + threshold = mdata->max_bw_per_pipe; + else + threshold = mdss_mdp_get_max_pipe_bw(pipe); + pr_debug("bw=%llu threshold=%u\n", pipe_bw, threshold); if (threshold && pipe_bw > threshold) {