static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total; int i; u32 max_clk_rate = 0, ab_total = 0, ib_total = 0; memset(perf, 0, sizeof(*perf)); if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } perf->mdp_clk_rate = mixer->width * v_total * fps; perf->mdp_clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(perf->mdp_clk_rate); if (!pinfo) { /* perf for bus writeback */ perf->ab_quota = fps * mixer->width * mixer->height * 3; perf->ib_quota = perf->ab_quota; } } for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) { struct mdss_mdp_perf_params tmp; pipe = mixer->stage_pipe[i]; if (pipe == NULL) continue; if (mdss_mdp_perf_calc_pipe(pipe, &tmp)) continue; ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; ib_total += tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; if (tmp.mdp_clk_rate > max_clk_rate) max_clk_rate = tmp.mdp_clk_rate; } perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT; perf->ib_quota += ib_total << MDSS_MDP_BUS_FACTOR_SHIFT; if (max_clk_rate > perf->mdp_clk_rate) perf->mdp_clk_rate = max_clk_rate; }
static int mdss_mdp_ctl_perf_commit(u32 flags) { struct mdss_mdp_ctl *ctl; int cnum; unsigned long clk_rate = 0; u64 bus_ab_quota = 0, bus_ib_quota = 0; if (!flags) { pr_err("nothing to update\n"); return -EINVAL; } mutex_lock(&mdss_mdp_ctl_lock); for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) { ctl = &mdss_mdp_ctl_list[cnum]; if (ctl->power_on) { bus_ab_quota += ctl->bus_ab_quota; bus_ib_quota += ctl->bus_ib_quota; if (ctl->clk_rate > clk_rate) clk_rate = ctl->clk_rate; } } if (flags & MDSS_MDP_PERF_UPDATE_BUS) { bus_ab_quota = bus_ab_quota << MDSS_MDP_BUS_FACTOR_SHIFT; bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota); bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT; if ((bus_ib_quota == 0) && (clk_rate > 0)) { /* allocate min bw for panel cmds if mdp is active */ bus_ib_quota = SZ_16M; } mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); } if (flags & MDSS_MDP_PERF_UPDATE_CLK) { clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate); pr_debug("update clk rate = %lu\n", clk_rate); mdss_mdp_set_clk_rate(clk_rate); } mutex_unlock(&mdss_mdp_ctl_lock); return 0; }
static int mdss_mdp_ctl_perf_commit(struct mdss_data_type *mdata, u32 flags) { struct mdss_mdp_ctl *ctl; int cnum; unsigned long clk_rate = 0; u64 bus_ab_quota = 0, bus_ib_quota = 0; if (!flags) { pr_err("nothing to update\n"); return -EINVAL; } mutex_lock(&mdss_mdp_ctl_lock); for (cnum = 0; cnum < mdata->nctl; cnum++) { ctl = mdata->ctl_off + cnum; if (ctl->power_on) { struct mdss_mdp_perf_params *perf = &ctl->cur_perf; bus_ab_quota += perf->ab_quota; bus_ib_quota += perf->ib_quota; if (perf->mdp_clk_rate > clk_rate) clk_rate = perf->mdp_clk_rate; } } if (flags & MDSS_MDP_PERF_UPDATE_BUS) { bus_ab_quota = bus_ib_quota; __mdss_mdp_ctrl_perf_ovrd(mdata, &bus_ab_quota, &bus_ib_quota); pr_debug("update ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota); mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); } if (flags & MDSS_MDP_PERF_UPDATE_CLK) { clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate); pr_debug("update clk rate = %lu HZ\n", clk_rate); mdss_mdp_set_clk_rate(clk_rate); } mutex_unlock(&mdss_mdp_ctl_lock); return 0; }
static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer, u32 *bus_ab_quota, u32 *bus_ib_quota, u32 *clk_rate) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total; int i; u32 max_clk_rate = 0, ab_total = 0; u32 ib_max = 0, ib_max_smp = 0; u32 ib_quota[MDSS_MDP_MAX_STAGE]; u32 v_region[MDSS_MDP_MAX_STAGE * 2]; *bus_ab_quota = 0; *bus_ib_quota = 0; *clk_rate = 0; if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } *clk_rate = mixer->width * v_total * fps; if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP) *clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate); if (!pinfo) { /* perf for bus writeback */ *bus_ab_quota = fps * mixer->width * mixer->height * 3; *bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT; *bus_ib_quota = *bus_ab_quota; } }
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total = 0; int i; u32 max_clk_rate = 0, ab_total = 0; u32 ib_max = 0; u32 ib_quota[MDSS_MDP_MAX_STAGE]; u32 v_region[MDSS_MDP_MAX_STAGE * 2]; u32 smp_bytes = 0; u64 smp_bw = 0; memset(perf, 0, sizeof(*perf)); if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } perf->mdp_clk_rate = mixer->width * v_total * fps; if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP) perf->mdp_clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(perf->mdp_clk_rate); if (!pinfo) { /* perf for bus writeback */ perf->ab_quota = fps * mixer->width * mixer->height * 3; perf->ib_quota = perf->ab_quota; } } memset(ib_quota, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE); memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2); for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) { struct mdss_mdp_perf_params tmp; pipe = mixer->stage_pipe[i]; if (pipe == NULL) continue; if (mdss_mdp_perf_calc_pipe(pipe, &tmp)) continue; smp_bytes += mdss_mdp_smp_get_size(pipe); ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; ib_quota[i] = tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; v_region[2*i] = pipe->dst.y; v_region[2*i + 1] = pipe->dst.y + pipe->dst.h; if (tmp.mdp_clk_rate > max_clk_rate) max_clk_rate = tmp.mdp_clk_rate; } /* * Sort the v_region array so the total display area can be * divided into individual regions. Check how many pipes fetch * data for each region and sum them up , then the worst case * of all regions is ib request. */ sort(v_region, MDSS_MDP_MAX_STAGE * 2, sizeof(u32), cmpu32, NULL); for (i = 1; i < MDSS_MDP_MAX_STAGE * 2; i++) { int j; u32 ib_max_region = 0; u32 y0, y1; pr_debug("v_region[%d]%d\n", i, v_region[i]); if (v_region[i] == v_region[i-1]) continue; y0 = (v_region[i-1]) ? v_region[i-1] + 1 : 0 ; y1 = v_region[i]; for (j = 0; j < MDSS_MDP_MAX_STAGE; j++) { if (!ib_quota[j]) continue; pipe = mixer->stage_pipe[j]; if (mdss_mdp_perf_is_overlap (y0, y1, pipe->dst.y, (pipe->dst.y + pipe->dst.h))) ib_max_region += ib_quota[j]; pr_debug("v[%d](%d, %d)pipe[%d](%d,%d)quota=%d max=%d\n", i, y0, y1, j, pipe->dst.y, pipe->dst.y + pipe->dst.h, ib_quota[j], ib_max_region); } ib_max = max(ib_max, ib_max_region); } perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT; perf->ib_quota += ib_max << MDSS_MDP_BUS_FACTOR_SHIFT; if (max_clk_rate > perf->mdp_clk_rate) perf->mdp_clk_rate = max_clk_rate; if (pinfo) { int vbp; /* * need to be able to at least fill the shared memory pool * during blanking period */ vbp = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width; smp_bw = smp_bytes * v_total * fps; do_div(smp_bw, vbp); if (smp_bw > perf->ib_quota) { pr_debug("replacing ib_quota=%llu with smp_bw=%llu\n", perf->ib_quota, smp_bw); perf->ib_quota = smp_bw; } } pr_debug("final mixer=%d clk_rate=%u bus ab=%llu ib=%llu smp=%llu\n", mixer->num, perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota, smp_bw); }