diff options
| author | Ingrid Gallardo <ingridg@codeaurora.org> | 2016-03-16 17:56:56 -0700 |
|---|---|---|
| committer | Kyle Yan <kyan@codeaurora.org> | 2016-04-28 16:43:58 -0700 |
| commit | 950ed52656ea6859a035ebffd19640d01bb72447 (patch) | |
| tree | dc0e98bfe42155a9fb8696464fc20699566ea6af | |
| parent | 49765e580abe02bb5786170322e1f135e03c24f9 (diff) | |
msm: mdss: add support for amortized prefill
Starting with sde 3.0, prefill bandwidth can
be amortized depending on the configuration.
This change adds support for this feature.
Change-Id: I501e11325365ec900a2ef8ee5bcbcd66f5647f64
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss.h | 5 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.c | 18 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 267 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_hwio.h | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pipe.c | 286 |
6 files changed, 462 insertions, 124 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index b5fd49de457b..a2046fd5b9cf 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -110,6 +110,10 @@ struct mdss_prefill_data { u32 post_scaler_pixels; u32 pp_pixels; u32 fbc_lines; + u32 ts_threshold; + u32 ts_end; + u32 ts_overhead; + struct mult_factor ts_rate; struct simplified_prefill_factors prefill_factors; }; @@ -185,6 +189,7 @@ enum mdss_qos_settings { MDSS_QOS_PER_PIPE_LUT, MDSS_QOS_SIMPLIFIED_PREFILL, MDSS_QOS_VBLANK_PANIC_CTRL, + MDSS_QOS_TS_PREFILL, MDSS_QOS_MAX, }; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 266fa8cc8192..253141072795 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1390,6 +1390,14 @@ void mdss_mdp_init_default_prefill_factors(struct mdss_data_type *mdata) mdata->prefill_data.prefill_factors.fmt_linear_factor = 1; mdata->prefill_data.prefill_factors.scale_factor = 1; mdata->prefill_data.prefill_factors.xtra_ff_factor = 2; + + if (test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map)) { + mdata->prefill_data.ts_threshold = 25; + mdata->prefill_data.ts_end = 8; + mdata->prefill_data.ts_rate.numer = 1; + mdata->prefill_data.ts_rate.denom = 4; + mdata->prefill_data.ts_overhead = 2; + } } static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) @@ -1514,7 +1522,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdata->per_pipe_ib_factor.denom = 5; mdata->apply_post_scale_bytes = false; mdata->hflip_buffer_reused = false; - mdata->min_prefill_lines = 21; + mdata->min_prefill_lines = 25; mdata->has_ubwc = true; mdata->pixel_ram_size = 50 * 1024; mdata->rects_per_sspp[MDSS_MDP_PIPE_TYPE_DMA] = 2; @@ -1525,6 +1533,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) set_bit(MDSS_QOS_OTLIM, mdata->mdss_qos_map); set_bit(MDSS_QOS_PER_PIPE_LUT, mdata->mdss_qos_map); set_bit(MDSS_QOS_SIMPLIFIED_PREFILL, mdata->mdss_qos_map); + set_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map); set_bit(MDSS_CAPS_YUV_CONFIG, mdata->mdss_caps_map); set_bit(MDSS_CAPS_SCM_RESTORE_NOT_REQUIRED, mdata->mdss_caps_map); @@ -1988,6 +1997,13 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev, mdata->prefill_data.prefill_factors.xtra_ff_factor); } + if (test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map)) { + SPRINT("amortizable_threshold=%d\n", + mdata->prefill_data.ts_threshold); + SPRINT("system_overhead_lines=%d\n", + mdata->prefill_data.ts_overhead); + } + if (mdata->props) SPRINT("props=%d\n", mdata->props); if (mdata->max_bw_low) diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 6abe08111334..85945890a7a4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1479,9 +1479,16 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, struct mdss_mdp_pipe **right_plist, int right_cnt); int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf, struct mdss_mdp_pipe *pipe); +u32 mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe, + struct mdss_rect *roi, u32 flags); +int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer, u32 *fps, u32 *v_total, + u32 *h_total, u32 *xres); int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_perf_params *perf, struct mdss_rect *roi, u32 flags); +bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata); u32 mdss_mdp_calc_latency_buf_bytes(bool is_yuv, bool is_bwc, bool is_tile, u32 src_w, u32 bpp, bool use_latency_buf_percentage, u32 smp_bytes, bool is_ubwc, bool is_nv12, bool is_hflip); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 46d8b4ccd3f4..8260a6ec38df 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -560,8 +560,13 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe, struct mdss_mdp_mixer *mixer; u32 rate, src_h; + /* + * when doing vertical decimation lines will be skipped, hence there is + * no need to account for these lines in MDP clock or request bus + * bandwidth to fetch them. + */ mixer = pipe->mixer_left; - src_h = src.h >> pipe->vert_deci; + src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci); if (mixer->rotator_mode) { @@ -594,6 +599,144 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe, return rate; } +static u32 mdss_mdp_get_rotator_fps(struct mdss_mdp_pipe *pipe) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + u32 fps; + + if (pipe->src.w >= 3840 || pipe->src.h >= 3840) + fps = ROTATOR_LOW_FRAME_RATE; + else if (mdata->traffic_shaper_en) + fps = DEFAULT_ROTATOR_FRAME_RATE; + else if (pipe->frame_rate) + fps = pipe->frame_rate; + else + fps = DEFAULT_FRAME_RATE; + + pr_debug("rotator fps:%d\n", fps); + + return fps; +} + +int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer, u32 *fps, u32 *v_total, + u32 *h_total, u32 *xres) +{ + + if (mixer->rotator_mode) { + *fps = mdss_mdp_get_rotator_fps(pipe); + } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { + struct mdss_panel_info *pinfo; + + if (!mixer->ctl) + return -EINVAL; + + pinfo = &mixer->ctl->panel_data->panel_info; + if (pinfo->type == MIPI_VIDEO_PANEL) { + *fps = pinfo->panel_max_fps; + *v_total = pinfo->panel_max_vtotal; + } else { + *fps = mdss_panel_get_framerate(pinfo); + *v_total = mdss_panel_get_vtotal(pinfo); + } + *xres = get_panel_width(mixer->ctl); + *h_total = mdss_panel_get_htotal(pinfo, false); + + if (is_pingpong_split(mixer->ctl->mfd)) + *h_total += mdss_panel_get_htotal( + &mixer->ctl->panel_data->next->panel_info, + false); + } else { + *v_total = mixer->height; + *xres = mixer->width; + *h_total = mixer->width; + } + + return 0; +} + +u32 mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe, + struct mdss_rect *roi, u32 flags) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_mixer *mixer = pipe->mixer_left; + struct mdss_rect src, dst; + u32 v_total, fps, h_total, xres; + u32 quota, src_h; + + if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total, + &h_total, &xres)) { + pr_err(" error retreiving the panel params!\n"); + return -EINVAL; + } + + dst = pipe->dst; + src = pipe->src; + + /* crop rectangles */ + if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req) + mdss_mdp_crop_rect(&src, &dst, roi); + + /* + * when doing vertical decimation lines will be skipped, hence there is + * no need to account for these lines in MDP clock or request bus + * bandwidth to fetch them. + */ + src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci); + + quota = fps * src.w * src_h; + + if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) + /* + * with decimation, chroma is not downsampled, this means we + * need to allocate bw for extra lines that will be fetched + */ + if (pipe->vert_deci) + quota *= 2; + else + quota = (quota * 3) / 2; + else + quota *= pipe->src_fmt->bpp; + + if (mixer->rotator_mode) { + if (test_bit(MDSS_QOS_OVERHEAD_FACTOR, + mdata->mdss_qos_map)) { + /* rotator read */ + quota = apply_comp_ratio_factor(quota, + pipe->src_fmt, &pipe->comp_ratio); + /* + * rotator write: here we are using src_fmt since + * current implementation only supports calculate + * bandwidth based in the source parameters. + * The correct fine-tuned calculation should use + * destination format and destination rectangles to + * calculate the bandwidth, but leaving this + * calculation as per current support. + */ + quota += apply_comp_ratio_factor(quota, + pipe->src_fmt, &pipe->comp_ratio); + } else { + quota *= 2; /* bus read + write */ + } + } else { + + quota = mult_frac(quota, v_total, dst.h); + if (!mixer->ctl->is_video_mode) + quota = mult_frac(quota, h_total, xres); + + if (test_bit(MDSS_QOS_OVERHEAD_FACTOR, + mdata->mdss_qos_map)) + quota = apply_comp_ratio_factor(quota, + pipe->src_fmt, &pipe->comp_ratio); + } + + pr_debug("quota:%d src.w:%d src.h%d comp:[%d, %d]\n", + quota, src.w, src_h, pipe->comp_ratio.numer, + pipe->comp_ratio.denom); + + return quota; +} + static inline bool validate_comp_ratio(struct mult_factor *factor) { return factor->numer && factor->denom; @@ -617,25 +760,6 @@ u32 apply_comp_ratio_factor(u32 quota, return quota; } -static u32 mdss_mdp_get_rotator_fps(struct mdss_mdp_pipe *pipe) -{ - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - u32 fps = DEFAULT_FRAME_RATE; - - if (pipe->frame_rate) - fps = pipe->frame_rate; - - if (mdata->traffic_shaper_en) - fps = DEFAULT_ROTATOR_FRAME_RATE; - - if (pipe->src.w >= 3840 || pipe->src.h >= 3840) - fps = ROTATOR_LOW_FRAME_RATE; - - pr_debug("rotator fps:%d\n", fps); - - return fps; -} - u64 mdss_mdp_perf_calc_simplified_prefill(struct mdss_mdp_pipe *pipe, u32 v_total, u32 fps, struct mdss_mdp_ctl *ctl) { @@ -712,13 +836,14 @@ exit: * fetches (bandwidth requirement) and processes data through MDP pipeline * (MDP clock requirement) based on frame size and scaling requirements. */ + int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_perf_params *perf, struct mdss_rect *roi, u32 flags) { struct mdss_mdp_mixer *mixer; int fps = DEFAULT_FRAME_RATE; - u32 quota, v_total = 0, src_h, xres = 0, h_total = 0; + u32 v_total = 0, src_h, xres = 0, h_total = 0; struct mdss_rect src, dst; bool is_fbc = false; struct mdss_mdp_prefill_params prefill_params; @@ -733,105 +858,45 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, dst = pipe->dst; src = pipe->src; - if (mixer->rotator_mode) { - fps = mdss_mdp_get_rotator_fps(pipe); - } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { - struct mdss_panel_info *pinfo; + /* + * when doing vertical decimation lines will be skipped, hence there is + * no need to account for these lines in MDP clock or request bus + * bandwidth to fetch them. + */ + src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci); + + if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total, + &h_total, &xres)) { + pr_err(" error retreiving the panel params!\n"); + return -EINVAL; + } + if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { if (!mixer->ctl) return -EINVAL; - - pinfo = &mixer->ctl->panel_data->panel_info; - if (pinfo->type == MIPI_VIDEO_PANEL) { - fps = pinfo->panel_max_fps; - v_total = pinfo->panel_max_vtotal; - } else { - fps = mdss_panel_get_framerate(pinfo); - v_total = mdss_panel_get_vtotal(pinfo); - } - xres = get_panel_width(mixer->ctl); - is_fbc = pinfo->fbc.enabled; - h_total = mdss_panel_get_htotal(pinfo, false); - - if (is_pingpong_split(mixer->ctl->mfd)) - h_total += mdss_panel_get_htotal( - &mixer->ctl->panel_data->next->panel_info, - false); - } else { - v_total = mixer->height; - xres = mixer->width; - h_total = mixer->width; + is_fbc = mixer->ctl->panel_data->panel_info.fbc.enabled; } mixer->ctl->frame_rate = fps; + /* crop rectangles */ if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req) mdss_mdp_crop_rect(&src, &dst, roi); pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps); - - /* - * when doing vertical decimation lines will be skipped, hence there is - * no need to account for these lines in MDP clock or request bus - * bandwidth to fetch them. - */ - src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci); - - quota = fps * src.w * src_h; - pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) dst_y=%d bpp=%d yuv=%d\n", pipe->src.w, src_h, pipe->dst.w, pipe->dst.h, pipe->dst.y, pipe->src_fmt->bpp, pipe->src_fmt->is_yuv); - if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) - /* - * with decimation, chroma is not downsampled, this means we - * need to allocate bw for extra lines that will be fetched - */ - if (pipe->vert_deci) - quota *= 2; - else - quota = (quota * 3) / 2; - else - quota *= pipe->src_fmt->bpp; - - if (mixer->rotator_mode) { - if (test_bit(MDSS_QOS_OVERHEAD_FACTOR, - mdata->mdss_qos_map)) { - /* rotator read */ - quota = apply_comp_ratio_factor(quota, - pipe->src_fmt, &pipe->comp_ratio); - /* - * rotator write: here we are using src_fmt since - * current implementation only supports calculate - * bandwidth based in the source parameters. - * The correct fine-tuned calculation should use - * destination format and destination rectangles to - * calculate the bandwidth, but leaving this - * calculation as per current support. - */ - quota += apply_comp_ratio_factor(quota, - pipe->src_fmt, &pipe->comp_ratio); - } else { - quota *= 2; /* bus read + write */ - } - } else { - - quota = mult_frac(quota, v_total, dst.h); - if (!mixer->ctl->is_video_mode) - quota = mult_frac(quota, h_total, xres); - - if (test_bit(MDSS_QOS_OVERHEAD_FACTOR, - mdata->mdss_qos_map)) - quota = apply_comp_ratio_factor(quota, - pipe->src_fmt, &pipe->comp_ratio); - } - - perf->bw_overlap = quota; + perf->bw_overlap = mdss_mdp_get_pipe_overlap_bw(pipe, roi, + flags); perf->mdp_clk_rate = get_pipe_mdp_clk_rate(pipe, src, dst, fps, v_total, flags); + pr_debug("bw:%llu clk:%d\n", perf->bw_overlap, + perf->mdp_clk_rate); + if (pipe->flags & MDP_SOLID_FILL) { perf->bw_overlap = 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index 7669a0be21c5..6c1a286b5d7e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -250,6 +250,9 @@ enum mdss_mdp_sspp_chroma_samp_type { #define MDSS_MDP_REG_SSPP_QOS_CTRL 0x06C #define MDSS_MDP_REG_SSPP_CDP_CTRL 0x134 #define MDSS_MDP_REG_SSPP_UBWC_ERROR_STATUS 0x138 +#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER 0x130 +#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_PREFILL 0x150 +#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154 #define MDSS_MDP_REG_SSPP_MULTI_REC_OP_MODE 0x170 #define MDSS_MDP_REG_SSPP_OUT_SIZE_REC1 0x160 diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 39d5666db4bf..a47477e2c9ef 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -39,8 +39,8 @@ #define PANIC_LUT_NRT_READ 0x0 #define ROBUST_LUT_NRT_READ 0xFFFF -/* Priority 2, no panic */ -#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000 +#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000 /* Priority 2, no panic */ +#define VBLANK_PANIC_CREQ_MASK 0x300030 #define QSEED3_DEFAULT_PRELAOD_H 0x4 #define QSEED3_DEFAULT_PRELAOD_V 0x3 @@ -60,6 +60,20 @@ static u32 mdss_mdp_calc_per_plane_num_blks(u32 ystride, struct mdss_mdp_pipe *pipe); static int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe); +/** + * enum mdss_mdp_pipe_qos - Different qos configurations for each pipe + * + * @MDSS_MDP_PIPE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe. + * @MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe. + * this configuration is mutually exclusive from VBLANK_CTRL. + * @MDSS_MDP_PIPE_QOS_PANIC_CTRL: Setup panic for the pipe. + */ +enum mdss_mdp_pipe_qos { + MDSS_MDP_PIPE_QOS_VBLANK_CTRL = BIT(0), + MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE = BIT(1), + MDSS_MDP_PIPE_QOS_PANIC_CTRL = BIT(2), +}; + static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe, u32 reg, u32 val) { @@ -222,6 +236,39 @@ static void mdss_mdp_config_pipe_panic_lut(struct mdss_mdp_pipe *pipe) panic_lut, robust_lut); } +static void mdss_mdp_pipe_qos_ctrl(struct mdss_mdp_pipe *pipe, + bool enable, u32 flags) +{ + u32 per_pipe_qos; + + per_pipe_qos = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL); + + if (flags & MDSS_MDP_PIPE_QOS_VBLANK_CTRL) { + per_pipe_qos |= VBLANK_PANIC_DEFAULT_CONFIG; + + if (enable) + per_pipe_qos |= BIT(16); + else + per_pipe_qos &= ~BIT(16); + } + + if (flags & MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE) { + /* this feature overrules previous VBLANK_CTRL */ + per_pipe_qos &= ~BIT(16); + per_pipe_qos &= ~VBLANK_PANIC_CREQ_MASK; /* clear vblank bits */ + } + + if (flags & MDSS_MDP_PIPE_QOS_PANIC_CTRL) { + if (enable) + per_pipe_qos |= BIT(0); + else + per_pipe_qos &= ~BIT(0); + } + + mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL, + per_pipe_qos); +} + /** * @mdss_mdp_pipe_panic_vblank_signal_ctrl - * @pipe: pointer to a pipe @@ -233,7 +280,6 @@ static void mdss_mdp_config_pipe_panic_lut(struct mdss_mdp_pipe *pipe) static int mdss_mdp_pipe_panic_vblank_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable) { - uint32_t panic_ctrl; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!mdata->has_panic_ctrl) @@ -247,17 +293,7 @@ static int mdss_mdp_pipe_panic_vblank_signal_ctrl(struct mdss_mdp_pipe *pipe, mutex_lock(&mdata->reg_lock); - panic_ctrl = mdss_mdp_pipe_read(pipe, - MDSS_MDP_REG_SSPP_QOS_CTRL); - - panic_ctrl |= VBLANK_PANIC_DEFAULT_CONFIG; - - if (enable) - panic_ctrl |= BIT(16); - else - panic_ctrl &= ~BIT(16); - mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL, - panic_ctrl); + mdss_mdp_pipe_qos_ctrl(pipe, enable, MDSS_MDP_PIPE_QOS_VBLANK_CTRL); mutex_unlock(&mdata->reg_lock); @@ -292,14 +328,10 @@ int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable) break; case MDSS_MDP_PANIC_PER_PIPE_CFG: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - panic_robust_ctrl = mdss_mdp_pipe_read(pipe, - MDSS_MDP_REG_SSPP_QOS_CTRL); - if (enable) - panic_robust_ctrl |= BIT(0); - else - panic_robust_ctrl &= ~BIT(0); - mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL, - panic_robust_ctrl); + + mdss_mdp_pipe_qos_ctrl(pipe, enable, + MDSS_MDP_PIPE_QOS_PANIC_CTRL); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); break; } @@ -2305,6 +2337,215 @@ static void mdss_mdp_set_ot_limit_pipe(struct mdss_mdp_pipe *pipe) mdss_mdp_set_ot_limit(&ot_params); } +bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata) +{ + /* do not apply for rotator or WB */ + return ((pipe->src.y > mdata->prefill_data.ts_threshold) && + (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)); +} + +static inline void __get_ordered_rects(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_pipe **low_pipe, + struct mdss_mdp_pipe **high_pipe) +{ + *low_pipe = pipe; + + if (pipe->multirect.mode == MDSS_MDP_PIPE_MULTIRECT_NONE) { + *high_pipe = NULL; + return; + } + + *high_pipe = pipe->multirect.next; + + /* if pipes are not in order, order them according to position */ + if ((*low_pipe)->src.y > (*high_pipe)->src.y) { + *low_pipe = pipe->multirect.next; + *high_pipe = pipe; + } +} + +static u32 __get_ts_count(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer, bool is_low_pipe) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + u32 ts_diff, ts_ypos; + struct mdss_mdp_pipe *low_pipe, *high_pipe; + u32 ts_count = 0; + u32 v_total, fps, h_total, xres; + + if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total, + &h_total, &xres)) { + pr_err(" error retreiving the panel params!\n"); + return -EINVAL; + } + + if (is_low_pipe) { + /* only calculate count if lower pipe is amortizable */ + if (mdss_mdp_is_amortizable_pipe(pipe, mixer, mdata)) { + ts_diff = mdata->prefill_data.ts_threshold - + mdata->prefill_data.ts_end; + ts_ypos = pipe->src.y - ts_diff; + ts_count = mult_frac(ts_ypos, 19200000, fps * v_total); + } + } else { /* high pipe */ + + /* only calculate count for high pipe in serial mode */ + if (pipe && + pipe->multirect.mode == MDSS_MDP_PIPE_MULTIRECT_SERIAL) { + __get_ordered_rects(pipe, &low_pipe, &high_pipe); + ts_count = high_pipe->src.y - low_pipe->src.y - 1; + ts_count = mult_frac(ts_count, 19200000, fps * v_total); + } + } + + return ts_count; +} + +static u32 __calc_ts_bytes(struct mdss_rect *src, u32 fps, u32 bpp) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + u32 ts_bytes; + + ts_bytes = src->h * src->w * + bpp * fps; + ts_bytes = mult_frac(ts_bytes, + mdata->prefill_data.ts_rate.numer, + mdata->prefill_data.ts_rate.denom); + ts_bytes /= 19200000; + + return ts_bytes; +} + +static u32 __get_ts_bytes(struct mdss_mdp_pipe *pipe, + struct mdss_mdp_mixer *mixer) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_pipe *low_pipe, *high_pipe; + u32 v_total, fps, h_total, xres; + u32 low_pipe_bw, high_pipe_bw; + u32 ts_bytes_low, ts_bytes_high; + u64 ts_bytes = 0; + + if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total, + &h_total, &xres)) { + pr_err(" error retreiving the panel params!\n"); + return -EINVAL; + } + + switch (pipe->multirect.mode) { + case MDSS_MDP_PIPE_MULTIRECT_NONE: + + /* do not amortize if pipe is not amortizable */ + if (!mdss_mdp_is_amortizable_pipe(pipe, mixer, mdata)) { + ts_bytes = 0; + goto exit; + } + + ts_bytes = __calc_ts_bytes(&pipe->src, fps, + pipe->src_fmt->bpp); + + break; + case MDSS_MDP_PIPE_MULTIRECT_PARALLEL: + + __get_ordered_rects(pipe, &low_pipe, &high_pipe); + + /* do not amortize if low_pipe is not amortizable */ + if (!mdss_mdp_is_amortizable_pipe(low_pipe, mixer, mdata)) { + ts_bytes = 0; + goto exit; + } + + /* calculate ts bytes as the sum of both rects */ + ts_bytes_low = __calc_ts_bytes(&low_pipe->src, fps, + low_pipe->src_fmt->bpp); + ts_bytes_high = __calc_ts_bytes(&low_pipe->src, fps, + high_pipe->src_fmt->bpp); + + ts_bytes = ts_bytes_low + ts_bytes_high; + break; + case MDSS_MDP_PIPE_MULTIRECT_SERIAL: + + __get_ordered_rects(pipe, &low_pipe, &high_pipe); + + /* calculate amortization using per-pipe bw */ + low_pipe_bw = mdss_mdp_get_pipe_overlap_bw(low_pipe, + &low_pipe->mixer_left->roi, 0); + high_pipe_bw = mdss_mdp_get_pipe_overlap_bw(high_pipe, + &high_pipe->mixer_left->roi, 0); + + /* amortize depending on the lower pipe amortization */ + if (mdss_mdp_is_amortizable_pipe(low_pipe, mixer, mdata)) + ts_bytes = max(low_pipe_bw, high_pipe_bw) / + 19200000; + else + ts_bytes = high_pipe_bw / 19200000; + break; + default: + pr_err("unknown multirect mode!\n"); + goto exit; + break; + }; + + ts_bytes &= 0xFF; + ts_bytes |= BIT(27) | BIT(31); +exit: + return (u32) ts_bytes; +} + +static int mdss_mdp_set_ts_pipe(struct mdss_mdp_pipe *pipe) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_mixer *mixer; + u32 ts_count_low = 0, ts_count_high = 0; + u32 ts_rec0, ts_rec1; + u32 ts_bytes = 0; + struct mdss_mdp_pipe *low_pipe = NULL; + struct mdss_mdp_pipe *high_pipe = NULL; + + if (!test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map)) + return 0; + + mixer = pipe->mixer_left; + if (!mixer) + return -EINVAL; + + if (!mixer->ctl) + return -EINVAL; + + if (!mdata->prefill_data.ts_threshold || + (mdata->prefill_data.ts_threshold < mdata->prefill_data.ts_end)) { + pr_err("invalid ts data!\n"); + return -EINVAL; + } + + /* high pipe will be null for non-multi rect cases */ + __get_ordered_rects(pipe, &low_pipe, &high_pipe); + + ts_count_low = __get_ts_count(low_pipe, mixer, true); + ts_count_high = __get_ts_count(high_pipe, mixer, false); + ts_bytes = __get_ts_bytes(pipe, mixer); + + if (low_pipe->multirect.num == MDSS_MDP_PIPE_RECT0) { + ts_rec0 = ts_count_low; + ts_rec1 = ts_count_high; + } else { + ts_rec0 = ts_count_high; + ts_rec1 = ts_count_low; + } + + mdss_mdp_pipe_qos_ctrl(pipe, false, MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE); + mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER, ts_bytes); + mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_PREFILL, + ts_rec0); + mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_REC1_PREFILL, + ts_rec1); + MDSS_XLOG(pipe->num, ts_bytes, ts_rec0, ts_rec1); + pr_debug("ts: pipe:%d bytes=0x%x count0=0x%x count1=0x%x\n", + pipe->num, ts_bytes, ts_rec0, ts_rec1); + return 0; +} + int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *src_data) { @@ -2432,6 +2673,7 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, mdss_mdp_pipe_panic_vblank_signal_ctrl(pipe, 1); mdss_mdp_pipe_panic_signal_ctrl(pipe, true); mdss_mdp_set_ot_limit_pipe(pipe); + mdss_mdp_set_ts_pipe(pipe); } } } |
