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

Commit 6286a5ab authored by Shivaraj Shetty's avatar Shivaraj Shetty Committed by Terence Hampson
Browse files

mdss: mdp3: Group together resource enable, simplifying xo shutdown



Grouping calls to prepare and unprepare of clocks along with enable
and disable for saving power in the case of static screen on command
mode panels. This makes sure that corresponding source clocks are
also disabled allowing xo shutdown to happen.

On top of that bandwidth request and iommu enable was grouped with
enabling/disabling clocks so that all display related clocks are
disable in static screen allowing for xo shutdown to happen.

Change-Id: I2db3844cbab5c41ea1bb37f5a5ed76c3c63e3a1d
Signed-off-by: default avatarTerence Hampson <thampson@codeaurora.org>
parent bfaea932
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "dsi_io_v2.h"
#include "dsi_host_v2.h"
#include "mdss_debug.h"
#include "mdp3.h"

#define DSI_POLL_SLEEP_US 1000
#define DSI_POLL_TIMEOUT_US 16000
@@ -971,7 +972,13 @@ int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
		mutex_unlock(&ctrl->cmd_mutex);
		return ret;
	}

	/*
	 * mdss interrupt is generated in mdp core clock domain
	 * mdp clock need to be enabled to receive dsi interrupt
	 * also, axi bus bandwidth need since dsi controller will
	 * fetch dcs commands from axi bus
	 */
	mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
	msm_dsi_clk_ctrl(&ctrl->panel_data, 1);

	if (0 == (req->flags & CMD_REQ_LP_MODE))
@@ -986,6 +993,7 @@ int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
		dsi_set_tx_power_mode(1);

	msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
	mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);

	mutex_unlock(&ctrl->cmd_mutex);
	return 0;
@@ -1431,13 +1439,16 @@ static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
						&byteclk_rate, &pclk_rate);
			msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
						byteclk_rate, pclk_rate);
			msm_dsi_prepare_clocks();
			msm_dsi_clk_enable();
		}
	} else {
		dsi_host_private->clk_count--;
		if (dsi_host_private->clk_count == 0) {
			msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask);
			msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
			msm_dsi_clk_disable();
			msm_dsi_unprepare_clocks();
			msm_dsi_ahb_ctrl(0);
		}
	}
+131 −68
Original line number Diff line number Diff line
@@ -191,11 +191,11 @@ static irqreturn_t mdp3_irq_handler(int irq, void *ptr)
	u32 mdp_status = 0;

	spin_lock(&mdata->irq_lock);
	if (!mdata->irq_mask)
	if (!mdata->irq_mask) {
		pr_err("spurious interrupt\n");

	clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
	clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
		spin_unlock(&mdata->irq_lock);
		return IRQ_HANDLED;
	}

	mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
	mdp_interrupt = mdp_status;
@@ -211,9 +211,6 @@ static irqreturn_t mdp3_irq_handler(int irq, void *ptr)
	}
	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status);

	clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
	clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);

	spin_unlock(&mdata->irq_lock);

	return IRQ_HANDLED;
@@ -281,19 +278,51 @@ void mdp3_irq_register(void)

	pr_debug("mdp3_irq_register\n");
	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
	mdp3_res->irq_ref_cnt++;
	if (mdp3_res->irq_ref_cnt == 1) {
		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
		enable_irq(mdp3_res->irq);
	}
	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}

void mdp3_irq_deregister(void)
{
	unsigned long flag;
	bool irq_enabled = true;

	pr_debug("mdp3_irq_deregister\n");
	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
	memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR);
	mdp3_res->irq_mask = 0;
	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
	mdp3_res->irq_ref_cnt--;
	/* This can happen if suspend is called first */
	if (mdp3_res->irq_ref_cnt < 0) {
		irq_enabled = false;
		mdp3_res->irq_ref_cnt = 0;
	}
	if (mdp3_res->irq_ref_cnt == 0 && irq_enabled)
		disable_irq_nosync(mdp3_res->irq);
	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}

void mdp3_irq_suspend(void)
{
	unsigned long flag;
	bool irq_enabled = true;

	pr_debug("%s\n", __func__);
	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
	mdp3_res->irq_ref_cnt--;
	if (mdp3_res->irq_ref_cnt < 0) {
		irq_enabled = false;
		mdp3_res->irq_ref_cnt = 0;
	}
	if (mdp3_res->irq_ref_cnt == 0 && irq_enabled) {
		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
		disable_irq_nosync(mdp3_res->irq);
	}
	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}

@@ -403,6 +432,12 @@ int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
	}
	bus_handle->current_bus_idx = bus_idx;
	rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx);

	if (!rc && ab_quota != 0 && ib_quota != 0) {
		bus_handle->restore_ab = ab_quota;
		bus_handle->restore_ib = ib_quota;
	}

	return rc;
}

@@ -425,10 +460,18 @@ static int mdp3_clk_update(u32 clk_idx, u32 enable)
	count = mdp3_res->clock_ref_count[clk_idx];
	if (count == 1 && enable) {
		pr_debug("clk=%d en=%d\n", clk_idx, enable);
		ret = clk_prepare(clk);
		if (ret) {
			pr_err("%s: Failed to prepare clock %d",
						__func__, clk_idx);
			mdp3_res->clock_ref_count[clk_idx]--;
			return ret;
		}
		ret = clk_enable(clk);
	} else if (count == 0) {
		pr_debug("clk=%d disable\n", clk_idx);
		clk_disable(clk);
		clk_unprepare(clk);
		ret = 0;
	} else if (count < 0) {
		pr_err("clk=%d count=%d\n", clk_idx, count);
@@ -580,54 +623,76 @@ int mdp3_clk_enable(int enable, int dsi_clk)
	return rc;
}

int mdp3_clk_prepare(void)
void mdp3_bus_bw_iommu_enable(int enable, int client)
{
	int rc = 0;
	struct mdp3_bus_handle_map *bus_handle;
	int client_idx;
	u64 ab, ib;
	int ref_cnt;

	mutex_lock(&mdp3_res->res_mutex);
	mdp3_res->clk_prepare_count++;
	if (mdp3_res->clk_prepare_count == 1) {
		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_AHB]);
		if (rc < 0)
			goto error0;
		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_CORE]);
		if (rc < 0)
			goto error1;
		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
		if (rc < 0)
			goto error2;
		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
		if (rc < 0)
			goto error3;
	if (client == MDP3_CLIENT_DMA_P) {
		client_idx  = MDP3_BUS_HANDLE_DMA;
	} else if (client == MDP3_CLIENT_PPP) {
		client_idx  = MDP3_BUS_HANDLE_PPP;
	} else {
		pr_err("invalid client %d\n", client);
		return;
	}
	mutex_unlock(&mdp3_res->res_mutex);
	return rc;

error3:
	clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
error2:
	clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
error1:
	clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
error0:
	mdp3_res->clk_prepare_count--;
	bus_handle = &mdp3_res->bus_handle[client_idx];
	if (bus_handle->handle < 1) {
		pr_err("invalid bus handle %d\n", bus_handle->handle);
		return;
	}
	mutex_lock(&mdp3_res->res_mutex);
	if (enable)
		bus_handle->ref_cnt++;
	else
		bus_handle->ref_cnt--;
	ref_cnt = bus_handle->ref_cnt;
	mutex_unlock(&mdp3_res->res_mutex);
	return rc;

	if (enable && ref_cnt == 1) {
		if (mdp3_res->allow_iommu_update)
			mdp3_iommu_enable(client);
		ab = bus_handle->restore_ab;
		ib = bus_handle->restore_ib;
		mdp3_bus_scale_set_quota(client, ab, ib);
	} else if (!enable && ref_cnt == 0) {
		mdp3_bus_scale_set_quota(client, 0, 0);
		mdp3_iommu_disable(client);
	} else if (ref_cnt < 0) {
		pr_err("Ref count < 0, bus client=%d, ref_cnt=%d",
				client_idx, ref_cnt);
	}
}

void mdp3_clk_unprepare(void)
int mdp3_res_update(int enable, int dsi_clk, int client)
{
	mutex_lock(&mdp3_res->res_mutex);
	mdp3_res->clk_prepare_count--;
	if (mdp3_res->clk_prepare_count == 0) {
		clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
		clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
		clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
		clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
	} else if (mdp3_res->clk_prepare_count < 0) {
		pr_err("mdp3 clk unprepare mismatch\n");
	int rc = 0;

	if (enable) {
		rc = mdp3_clk_enable(enable, dsi_clk);
		if (rc < 0) {
			pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n",
				enable, dsi_clk);
			goto done;
		}
	mutex_unlock(&mdp3_res->res_mutex);
		mdp3_irq_register();
		mdp3_bus_bw_iommu_enable(enable, client);
	} else {
		mdp3_bus_bw_iommu_enable(enable, client);
		mdp3_irq_suspend();
		rc = mdp3_clk_enable(enable, dsi_clk);
		if (rc < 0) {
			pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n",
				enable, dsi_clk);
			goto done;
		}
	}

done:
	return rc;
}

int mdp3_get_mdp_dsi_clk(void)
@@ -646,7 +711,6 @@ int mdp3_put_mdp_dsi_clk(void)
	int rc;
	mutex_lock(&mdp3_res->res_mutex);
	rc = mdp3_clk_update(MDP3_CLK_DSI, 0);
	clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
	mutex_unlock(&mdp3_res->res_mutex);
	return rc;
}
@@ -1847,6 +1911,7 @@ static int mdp3_is_display_on(struct mdss_panel_data *pdata)
static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
{
	struct mdss_panel_info *panel_info = &pdata->panel_info;
	struct mdp3_bus_handle_map *bus_handle;
	u64 ab, ib;
	int rc;

@@ -1858,26 +1923,23 @@ static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
	mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE,
			MDP3_CLIENT_DMA_P);

	rc = mdp3_clk_prepare();
	if (rc) {
		pr_err("fail to prepare clk\n");
		return rc;
	}

	rc = mdp3_clk_enable(1, 1);
	if (rc) {
		pr_err("fail to enable clk\n");
		mdp3_clk_unprepare();
		return rc;
	bus_handle = &mdp3_res->bus_handle[MDP3_BUS_HANDLE_DMA];
	if (bus_handle->handle < 1) {
		pr_err("invalid bus handle %d\n", bus_handle->handle);
		return -EINVAL;
	}

	ab = panel_info->xres * panel_info->yres * 4;
	ab *= panel_info->mipi.frame_rate;
	ib = (ab * 3) / 2;
	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
	bus_handle->restore_ab = ab;
	bus_handle->restore_ib = ib;

	rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
	if (rc) {
		pr_err("fail to request bus bandwidth\n");
		goto splash_on_err;
		pr_err("fail to enable clk\n");
		return rc;
	}

	rc = mdp3_ppp_init();
@@ -1886,8 +1948,6 @@ static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
		goto splash_on_err;
	}

	mdp3_irq_register();

	if (pdata->event_handler) {
		rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
					NULL);
@@ -1907,10 +1967,9 @@ static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
	return 0;

splash_on_err:
	if (mdp3_clk_enable(0, 1))
	if (mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P))
		pr_err("%s: Unable to disable mdp3 clocks\n", __func__);

	mdp3_clk_unprepare();
	return rc;
}

@@ -1930,6 +1989,12 @@ static int mdp3_panel_register_done(struct mdss_panel_data *pdata)
			rc = mdp3_continuous_splash_on(pdata);
		}
	}
	/*
	 * We want to prevent iommu from being enabled if there is
	 * continue splash screen. This would have happened in
	 * res_update in continuous_splash_on without this flag.
	 */
	mdp3_res->allow_iommu_update = true;
	return rc;
}

@@ -1944,11 +2009,9 @@ static int mdp3_debug_dump_stats(void *data, char *buf, int len)
static void mdp3_debug_enable_clock(int on)
{
	if (on) {
		mdp3_clk_prepare();
		mdp3_clk_enable(1, 0);
	} else {
		mdp3_clk_enable(0, 0);
		mdp3_clk_unprepare();
	}
}

+6 −2
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ struct mdp3_bus_handle_map {
	struct msm_bus_paths *usecases;
	struct msm_bus_scale_pdata *scale_pdata;
	int current_bus_idx;
	int ref_cnt;
	u64 restore_ab;
	u64 restore_ib;
	u32 handle;
};

@@ -133,6 +136,7 @@ struct mdp3_hw_resource {
	struct ion_client *ion_client;
	struct mdp3_iommu_domain_map *domains;
	struct mdp3_iommu_ctx_map *iommu_contexts;
	bool allow_iommu_update;
	struct ion_handle *ion_handle;
	struct mutex iommu_lock;
	struct rb_root iommu_root;
@@ -143,6 +147,7 @@ struct mdp3_hw_resource {
	spinlock_t irq_lock;
	u32 irq_ref_count[MDP3_MAX_INTR];
	u32 irq_mask;
	int irq_ref_cnt;
	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
	u32 underrun_cnt;

@@ -182,8 +187,7 @@ void mdp3_irq_register(void);
void mdp3_irq_deregister(void);
int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
int mdp3_clk_enable(int enable, int dsi_clk);
int mdp3_clk_prepare(void);
void mdp3_clk_unprepare(void);
int mdp3_res_update(int enable, int dsi_clk, int client);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data, int client);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
+6 −34
Original line number Diff line number Diff line
@@ -338,7 +338,7 @@ static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable)
				(!enable && session->clk_on == 1)) {
		rc = panel->event_handler(panel,
			MDSS_EVENT_PANEL_CLK_CTRL, (void *)enable);
		rc |= mdp3_clk_enable(enable, 1);
		rc |= mdp3_res_update(enable, 1, MDP3_CLIENT_DMA_P);
	} else {
		pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
	}
@@ -374,24 +374,15 @@ static int mdp3_ctrl_res_req_clk(struct msm_fb_data_type *mfd, int status)
		mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
				MDP3_CLIENT_DMA_P);

		rc = mdp3_clk_prepare();
		if (rc) {
			pr_err("mdp3 clk prepare fail\n");
			return rc;
		}

		rc = mdp3_clk_enable(1, 1);
		rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
		if (rc) {
			pr_err("mdp3 clk enable fail\n");
			mdp3_clk_unprepare();
			return rc;
		}
	} else {
		rc = mdp3_clk_enable(0, 1);
		rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
		if (rc)
			pr_err("mdp3 clk disable fail\n");
		else
			mdp3_clk_unprepare();
	}
	return rc;
}
@@ -587,12 +578,6 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
	mdp3_ctrl_notifier_register(mdp3_session,
		&mdp3_session->mfd->mdp_sync_pt_data.notifier);

	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
	if (rc) {
		pr_err("fail to attach MDP DMA SMMU\n");
		goto on_error;
	}

	/* request bus bandwidth before DSI DMA traffic */
	rc = mdp3_ctrl_res_req_bus(mfd, 1);
	if (rc) {
@@ -615,8 +600,6 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
		goto on_error;
	}

	mdp3_irq_register();

	rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
	if (rc) {
		pr_err("dma init failed\n");
@@ -634,7 +617,6 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
		pr_err("display interface init failed\n");
		goto on_error;
	}

	mdp3_session->clk_on = 1;

	mdp3_session->first_commit = true;
@@ -686,7 +668,7 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)

	pr_debug("mdp3_ctrl_off stop clock\n");
	if (mdp3_session->clk_on) {
		rc = mdp3_clk_enable(0, 1);
		rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
		if (rc)
			pr_err("mdp clock resource release failed\n");

@@ -697,16 +679,6 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
		if (rc)
			pr_err("fail to turn off the panel\n");
	}
	mdp3_clk_unprepare();

	pr_debug("mdp3_ctrl_off release bus\n");
	rc = mdp3_ctrl_res_req_bus(mfd, 0);
	if (rc)
		pr_err("mdp bus resource release failed\n");

	rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
	if (rc)
		pr_err("fail to dettach MDP DMA SMMU\n");

	mdp3_ctrl_notifier_unregister(mdp3_session,
		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
@@ -1316,7 +1288,7 @@ static int mdp3_histogram_start(struct mdp3_session_data *session,
		return -EBUSY;
	}

	mdp3_clk_enable(1, 0);
	mdp3_res_update(1, 0, MDP3_CLIENT_DMA_P);
	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
	if (ret) {
		pr_err("mdp3_histogram_start reset error\n");
@@ -1342,7 +1314,7 @@ static int mdp3_histogram_start(struct mdp3_session_data *session,
	session->histo_status = 1;

histogram_start_err:
	mdp3_clk_enable(0, 0);
	mdp3_res_update(0, 0, MDP3_CLIENT_DMA_P);
	mutex_unlock(&session->histo_lock);
	return ret;
}
+2 −13
Original line number Diff line number Diff line
@@ -386,14 +386,14 @@ int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
			ab = req_bw;
	}
	mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
	rc = mdp3_clk_enable(on_off, 0);
	rc = mdp3_res_update(on_off, 0, MDP3_CLIENT_PPP);
	if (rc < 0) {
		pr_err("%s: mdp3_clk_enable failed\n", __func__);
		return rc;
	}
	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
	if (rc < 0) {
		mdp3_clk_enable(!on_off, 0);
		mdp3_res_update(!on_off, 0, MDP3_CLIENT_PPP);
		pr_err("%s: scale_set_quota failed\n", __func__);
		return rc;
	}
@@ -1039,14 +1039,10 @@ void mdp3_free_fw_timer_func(unsigned long arg)
static void mdp3_free_bw_wq_handler(struct work_struct *work)
{
	struct msm_fb_data_type *mfd = ppp_stat->mfd;
	int rc;

	mutex_lock(&ppp_stat->config_ppp_mutex);
	if (ppp_stat->bw_on) {
		mdp3_ppp_turnon(mfd, 0);
		rc = mdp3_iommu_disable(MDP3_CLIENT_PPP);
		if (rc < 0)
			WARN(1, "Unable to disable ppp iommu\n");
	}
	mutex_unlock(&ppp_stat->config_ppp_mutex);
}
@@ -1065,16 +1061,9 @@ static void mdp3_ppp_blit_wq_handler(struct work_struct *work)
	}

	if (!ppp_stat->bw_on) {
		rc = mdp3_iommu_enable(MDP3_CLIENT_PPP);
		if (rc < 0) {
			mutex_unlock(&ppp_stat->config_ppp_mutex);
			pr_err("%s: mdp3_iommu_enable failed\n", __func__);
			return;
		}
		ppp_stat->bw_optimal = mdp3_optimal_bw(req->count);
		mdp3_ppp_turnon(mfd, 1);
		if (rc < 0) {
			mdp3_iommu_disable(MDP3_CLIENT_PPP);
			mutex_unlock(&ppp_stat->config_ppp_mutex);
			pr_err("%s: Enable ppp resources failed\n", __func__);
			return;