Loading drivers/video/msm/mdss/mdss_mdp.h +7 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,7 @@ struct mdss_mdp_ctl { int force_screen_state; struct mdss_mdp_perf_params cur_perf; struct mdss_mdp_perf_params new_perf; int perf_status; struct mdss_data_type *mdata; struct msm_fb_data_type *mfd; Loading @@ -184,6 +185,7 @@ struct mdss_mdp_ctl { struct mdss_mdp_mixer *mixer_right; struct mutex lock; struct mutex *shared_lock; spinlock_t spin_lock; struct mdss_panel_data *panel_data; struct mdss_mdp_vsync_handler vsync_handler; Loading Loading @@ -557,6 +559,11 @@ int mdss_mdp_scan_pipes(void); int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe); void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl); void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl); void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl); struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator); int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer); struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux); Loading drivers/video/msm/mdss/mdss_mdp_ctl.c +154 −21 Original line number Diff line number Diff line Loading @@ -570,6 +570,156 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl, perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes); } static bool mdss_mdp_ctl_perf_bw_released(struct mdss_mdp_ctl *ctl) { unsigned long flags; bool released = false; if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return released; spin_lock_irqsave(&ctl->spin_lock, flags); if (ctl->perf_status == 0) { released = true; ctl->perf_status++; } else if (ctl->perf_status <= 2) { ctl->perf_status++; } else { pr_err("pervious commit was not done\n"); } pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock_irqrestore(&ctl->spin_lock, flags); return released; } /** * @mdss_mdp_ctl_perf_taken() - indicates a committed buffer is taken * by h/w * @ctl - pointer to ctl data structure * * A committed buffer to be displayed is taken at a vsync or reader * pointer interrupt by h/w. This function must be called in vsync * interrupt context to indicate the buf status is changed. */ void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl) { if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; spin_lock(&ctl->spin_lock); if (ctl->perf_status) ctl->perf_status++; pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock(&ctl->spin_lock); } /** * @mdss_mdp_ctl_perf_done() - indicates a committed buffer is * displayed, so resources such as * bandwidth that are associated to this * buffer can be released. * @ctl - pointer to a ctl * * When pingping done interrupt is trigged, mdp finishes displaying a * buffer which was committed by user and taken by h/w and calling * this function to clear those two states. This function must be * called in pinppong done interrupt context. */ void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl) { if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; spin_lock(&ctl->spin_lock); if (ctl->perf_status) { ctl->perf_status--; if (ctl->perf_status) ctl->perf_status--; } pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock(&ctl->spin_lock); } static inline void mdss_mdp_ctl_perf_update_bus(struct mdss_mdp_ctl *ctl) { u64 bw_sum_of_intfs = 0; u64 bus_ab_quota, bus_ib_quota; struct mdss_data_type *mdata; int i; if (!ctl || !ctl->mdata) return; mdata = ctl->mdata; for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl; ctl = mdata->ctl_off + i; if (ctl->power_on) { bw_sum_of_intfs += ctl->cur_perf.bw_ctl; pr_debug("c=%d bw=%llu\n", ctl->num, ctl->cur_perf.bw_ctl); } } bus_ib_quota = bw_sum_of_intfs; bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs); mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota); } /** * @mdss_mdp_ctl_perf_release_bw() - request zero bandwidth * @ctl - pointer to a ctl * * Function checks a state variable for the ctl, if all pending commit * requests are done, meanning no more bandwidth is needed, release * bandwidth request. */ void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl) { unsigned long flags; int need_release = 0; struct mdss_data_type *mdata; int i; /* only do this for command panel */ if (!ctl || !ctl->mdata || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; mutex_lock(&mdss_mdp_ctl_lock); mdata = ctl->mdata; /* * If video interface present, cmd panel bandwidth cannot be * released. */ for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl = mdata->ctl_off + i; if (ctl->power_on && ctl->is_video_mode) { mutex_unlock(&mdss_mdp_ctl_lock); return; } } spin_lock_irqsave(&ctl->spin_lock, flags); if (!ctl->perf_status) need_release = 1; pr_debug("need release=%d\n", need_release); spin_unlock_irqrestore(&ctl->spin_lock, flags); if (need_release) { ctl->cur_perf.bw_ctl = 0; ctl->new_perf.bw_ctl = 0; mdss_mdp_ctl_perf_update_bus(ctl); } mutex_unlock(&mdss_mdp_ctl_lock); } static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, int params_changed) { Loading @@ -587,9 +737,8 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, new = &ctl->new_perf; if (ctl->power_on) { if (params_changed) if (params_changed || mdss_mdp_ctl_perf_bw_released(ctl)) mdss_mdp_perf_calc_ctl(ctl, new); /* * if params have just changed delay the update until * later once the hw configuration has been flushed to Loading Loading @@ -617,25 +766,8 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, update_clk = 1; } if (update_bus) { u64 bw_sum_of_intfs = 0; u64 bus_ab_quota = 0, bus_ib_quota = 0; int i; for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl; ctl = mdata->ctl_off + i; if (ctl->power_on) { bw_sum_of_intfs += ctl->cur_perf.bw_ctl; pr_debug("c=%d bw=%llu\n", ctl->num, ctl->cur_perf.bw_ctl); } } bus_ib_quota = bw_sum_of_intfs; bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs); mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota); } if (update_bus) mdss_mdp_ctl_perf_update_bus(ctl); if (update_clk) { u32 clk_rate = 0; Loading Loading @@ -672,6 +804,7 @@ static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata, ctl->ref_cnt++; ctl->mdata = mdata; mutex_init(&ctl->lock); spin_lock_init(&ctl->spin_lock); BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head); pr_debug("alloc ctl_num=%d\n", ctl->num); break; Loading drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +9 −2 Original line number Diff line number Diff line /* Copyright (c) 2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -227,6 +227,8 @@ static void mdss_mdp_cmd_readptr_done(void *arg) return; } mdss_mdp_ctl_perf_taken(ctl); vsync_time = ktime_get(); ctl->vsync_cnt++; Loading Loading @@ -288,6 +290,8 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) return; } mdss_mdp_ctl_perf_done(ctl); spin_lock(&ctx->clk_lock); list_for_each_entry(tmp, &ctx->vsync_handlers, list) { if (tmp->enabled && tmp->cmd_post_flush) Loading Loading @@ -320,9 +324,12 @@ static void pingpong_done_work(struct work_struct *work) struct mdss_mdp_cmd_ctx *ctx = container_of(work, typeof(*ctx), pp_done_work); if (ctx->ctl) if (ctx->ctl) { while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0)) mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE); mdss_mdp_ctl_perf_release_bw(ctx->ctl); } } static void clk_ctrl_work(struct work_struct *work) Loading Loading
drivers/video/msm/mdss/mdss_mdp.h +7 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,7 @@ struct mdss_mdp_ctl { int force_screen_state; struct mdss_mdp_perf_params cur_perf; struct mdss_mdp_perf_params new_perf; int perf_status; struct mdss_data_type *mdata; struct msm_fb_data_type *mfd; Loading @@ -184,6 +185,7 @@ struct mdss_mdp_ctl { struct mdss_mdp_mixer *mixer_right; struct mutex lock; struct mutex *shared_lock; spinlock_t spin_lock; struct mdss_panel_data *panel_data; struct mdss_mdp_vsync_handler vsync_handler; Loading Loading @@ -557,6 +559,11 @@ int mdss_mdp_scan_pipes(void); int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe); void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl); void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl); void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl); struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator); int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer); struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux); Loading
drivers/video/msm/mdss/mdss_mdp_ctl.c +154 −21 Original line number Diff line number Diff line Loading @@ -570,6 +570,156 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl, perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes); } static bool mdss_mdp_ctl_perf_bw_released(struct mdss_mdp_ctl *ctl) { unsigned long flags; bool released = false; if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return released; spin_lock_irqsave(&ctl->spin_lock, flags); if (ctl->perf_status == 0) { released = true; ctl->perf_status++; } else if (ctl->perf_status <= 2) { ctl->perf_status++; } else { pr_err("pervious commit was not done\n"); } pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock_irqrestore(&ctl->spin_lock, flags); return released; } /** * @mdss_mdp_ctl_perf_taken() - indicates a committed buffer is taken * by h/w * @ctl - pointer to ctl data structure * * A committed buffer to be displayed is taken at a vsync or reader * pointer interrupt by h/w. This function must be called in vsync * interrupt context to indicate the buf status is changed. */ void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl) { if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; spin_lock(&ctl->spin_lock); if (ctl->perf_status) ctl->perf_status++; pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock(&ctl->spin_lock); } /** * @mdss_mdp_ctl_perf_done() - indicates a committed buffer is * displayed, so resources such as * bandwidth that are associated to this * buffer can be released. * @ctl - pointer to a ctl * * When pingping done interrupt is trigged, mdp finishes displaying a * buffer which was committed by user and taken by h/w and calling * this function to clear those two states. This function must be * called in pinppong done interrupt context. */ void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl) { if (!ctl || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; spin_lock(&ctl->spin_lock); if (ctl->perf_status) { ctl->perf_status--; if (ctl->perf_status) ctl->perf_status--; } pr_debug("perf_status=%d\n", ctl->perf_status); spin_unlock(&ctl->spin_lock); } static inline void mdss_mdp_ctl_perf_update_bus(struct mdss_mdp_ctl *ctl) { u64 bw_sum_of_intfs = 0; u64 bus_ab_quota, bus_ib_quota; struct mdss_data_type *mdata; int i; if (!ctl || !ctl->mdata) return; mdata = ctl->mdata; for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl; ctl = mdata->ctl_off + i; if (ctl->power_on) { bw_sum_of_intfs += ctl->cur_perf.bw_ctl; pr_debug("c=%d bw=%llu\n", ctl->num, ctl->cur_perf.bw_ctl); } } bus_ib_quota = bw_sum_of_intfs; bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs); mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota); } /** * @mdss_mdp_ctl_perf_release_bw() - request zero bandwidth * @ctl - pointer to a ctl * * Function checks a state variable for the ctl, if all pending commit * requests are done, meanning no more bandwidth is needed, release * bandwidth request. */ void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl) { unsigned long flags; int need_release = 0; struct mdss_data_type *mdata; int i; /* only do this for command panel */ if (!ctl || !ctl->mdata || !ctl->panel_data || (ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) return; mutex_lock(&mdss_mdp_ctl_lock); mdata = ctl->mdata; /* * If video interface present, cmd panel bandwidth cannot be * released. */ for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl = mdata->ctl_off + i; if (ctl->power_on && ctl->is_video_mode) { mutex_unlock(&mdss_mdp_ctl_lock); return; } } spin_lock_irqsave(&ctl->spin_lock, flags); if (!ctl->perf_status) need_release = 1; pr_debug("need release=%d\n", need_release); spin_unlock_irqrestore(&ctl->spin_lock, flags); if (need_release) { ctl->cur_perf.bw_ctl = 0; ctl->new_perf.bw_ctl = 0; mdss_mdp_ctl_perf_update_bus(ctl); } mutex_unlock(&mdss_mdp_ctl_lock); } static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, int params_changed) { Loading @@ -587,9 +737,8 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, new = &ctl->new_perf; if (ctl->power_on) { if (params_changed) if (params_changed || mdss_mdp_ctl_perf_bw_released(ctl)) mdss_mdp_perf_calc_ctl(ctl, new); /* * if params have just changed delay the update until * later once the hw configuration has been flushed to Loading Loading @@ -617,25 +766,8 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, update_clk = 1; } if (update_bus) { u64 bw_sum_of_intfs = 0; u64 bus_ab_quota = 0, bus_ib_quota = 0; int i; for (i = 0; i < mdata->nctl; i++) { struct mdss_mdp_ctl *ctl; ctl = mdata->ctl_off + i; if (ctl->power_on) { bw_sum_of_intfs += ctl->cur_perf.bw_ctl; pr_debug("c=%d bw=%llu\n", ctl->num, ctl->cur_perf.bw_ctl); } } bus_ib_quota = bw_sum_of_intfs; bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs); mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota); pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota); } if (update_bus) mdss_mdp_ctl_perf_update_bus(ctl); if (update_clk) { u32 clk_rate = 0; Loading Loading @@ -672,6 +804,7 @@ static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata, ctl->ref_cnt++; ctl->mdata = mdata; mutex_init(&ctl->lock); spin_lock_init(&ctl->spin_lock); BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head); pr_debug("alloc ctl_num=%d\n", ctl->num); break; Loading
drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +9 −2 Original line number Diff line number Diff line /* Copyright (c) 2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -227,6 +227,8 @@ static void mdss_mdp_cmd_readptr_done(void *arg) return; } mdss_mdp_ctl_perf_taken(ctl); vsync_time = ktime_get(); ctl->vsync_cnt++; Loading Loading @@ -288,6 +290,8 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) return; } mdss_mdp_ctl_perf_done(ctl); spin_lock(&ctx->clk_lock); list_for_each_entry(tmp, &ctx->vsync_handlers, list) { if (tmp->enabled && tmp->cmd_post_flush) Loading Loading @@ -320,9 +324,12 @@ static void pingpong_done_work(struct work_struct *work) struct mdss_mdp_cmd_ctx *ctx = container_of(work, typeof(*ctx), pp_done_work); if (ctx->ctl) if (ctx->ctl) { while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0)) mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE); mdss_mdp_ctl_perf_release_bw(ctx->ctl); } } static void clk_ctrl_work(struct work_struct *work) Loading