Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 714bc2c4 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: release mdp bandwidth voting for command mode when idle"

parents e16f84de bfd73843
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
+154 −21
Original line number Diff line number Diff line
@@ -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)
{
@@ -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
@@ -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;
@@ -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;
+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
@@ -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++;

@@ -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)
@@ -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)