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

Commit d6171217 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: move ULPS configuration to DSI clock control"

parents c0ab746c eb03a4e9
Loading
Loading
Loading
Loading
+88 −170
Original line number Diff line number Diff line
@@ -76,19 +76,21 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
				panel_data);
	pr_debug("%s: enable=%d\n", __func__, enable);

	if (pdata->panel_info.dynamic_switch_pending) {
	/*
		 * Current implementation of dynamic mode switch
		 * relies on the GDSC to be disabled while switching.
	 * If a dynamic mode switch is pending, the regulators should not
	 * be turned off or on.
	 */
		msm_dss_enable_vreg(
			ctrl_pdata->power_data[DSI_CORE_PM].vreg_config,
			ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable);
	if (pdata->panel_info.dynamic_switch_pending)
		return 0;
	}

	if (enable) {
		for (i = 0; i < DSI_MAX_PM; i++) {
			/*
			 * Core power module will be enabled when the
			 * clocks are enabled
			 */
			if (DSI_CORE_PM == i)
				continue;
			ret = msm_dss_enable_vreg(
				ctrl_pdata->power_data[i].vreg_config,
				ctrl_pdata->power_data[i].num_vreg, 1);
@@ -121,6 +123,12 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
			pr_debug("reset disable: pinctrl not enabled\n");

		for (i = DSI_MAX_PM - 1; i >= 0; i--) {
			/*
			 * Core power module will be disabled when the
			 * clocks are disabled
			 */
			if (DSI_CORE_PM == i)
				continue;
			ret = msm_dss_enable_vreg(
				ctrl_pdata->power_data[i].vreg_config,
				ctrl_pdata->power_data[i].num_vreg, 0);
@@ -483,85 +491,93 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
	}
}

static inline bool __mdss_dsi_ulps_feature_enabled(
	struct mdss_panel_data *pdata)
{
	return pdata->panel_info.ulps_feature_enabled;
}

static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
	int enable)
int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable)
{
	int ret = 0;
	struct mdss_panel_data *pdata = NULL;
	struct mipi_panel_info *pinfo = NULL;
	u32 lane_status = 0;
	u32 active_lanes = 0;
	u32 regval = 0;
	struct mdss_panel_info *pinfo;
	struct mipi_panel_info *mipi;
	u32 lane_status = 0, regval;
	u32 active_lanes = 0, clamp_reg;

	if (!ctrl_pdata) {
		pr_err("%s: invalid input\n", __func__);
		return -EINVAL;
	}

	if (&ctrl_pdata->mmss_misc_io == NULL) {
		pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
		return -EINVAL;
	}

	pdata = &ctrl_pdata->panel_data;
	if (!pdata) {
		pr_err("%s: Invalid panel data\n", __func__);
		return -EINVAL;
	}
	pinfo = &pdata->panel_info.mipi;
	pinfo = &pdata->panel_info;
	mipi = &pinfo->mipi;

	if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
	if (!mdss_dsi_ulps_feature_enabled(pdata)) {
		pr_debug("%s: ULPS feature not supported. enable=%d\n",
			__func__, enable);
		return -ENOTSUPP;
	}

	if (enable && !ctrl_pdata->ulps) {
		/* No need to configure ULPS mode when entering suspend state */
		if (!pdata->panel_info.panel_power_on) {
			pr_err("%s: panel off. returning\n", __func__);
			goto error;
		}

		if (__mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) {
			pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
	/*
	 * No need to enter ULPS when transitioning from splash screen to
	 * boot animation since it is expected that the clocks would be turned
	 * right back on.
	 */
	if (pinfo->cont_splash_enabled) {
		pr_debug("%s: skip ULPS config with splash screen enabled\n",
			__func__);
			ret = -EPERM;
			goto error;
		return 0;
	}

		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
		if (ret) {
			pr_err("%s: Failed to enable clocks. rc=%d\n",
				__func__, ret);
			goto error;
	/* clock lane will always be programmed for ulps and will be clamped */
	active_lanes = BIT(4);
	clamp_reg = BIT(8) | BIT(9);
	/*
	 * make a note of all active data lanes for which ulps entry/exit
	 * as well as DSI clamps are needed
	 */
	if (mipi->data_lane0) {
		active_lanes |= BIT(0);
		clamp_reg |= (BIT(0) | BIT(1));
	}
	if (mipi->data_lane1) {
		active_lanes |= BIT(1);
		clamp_reg |= (BIT(2) | BIT(3));
	}
	if (mipi->data_lane2) {
		active_lanes |= BIT(2);
		clamp_reg |= (BIT(4) | BIT(5));
	}
	if (mipi->data_lane3) {
		active_lanes |= BIT(3);
		clamp_reg |= (BIT(6) | BIT(7));
	}

	pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n",
		__func__, (enable ? "on" : "off"), ctrl_pdata->ndx,
		active_lanes);

	if (enable && !ctrl_pdata->ulps) {
		/*
		 * ULPS Entry Request.
		 * Wait for a short duration to ensure that the lanes
		 * enter ULP state.
		 */
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
		usleep(100);

		/* Check to make sure that all active data lanes are in ULPS */
		if (pinfo->data_lane3)
			active_lanes |= BIT(11);
		if (pinfo->data_lane2)
			active_lanes |= BIT(10);
		if (pinfo->data_lane1)
			active_lanes |= BIT(9);
		if (pinfo->data_lane0)
			active_lanes |= BIT(8);
		active_lanes |= BIT(12); /* clock lane */
		lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
		if (lane_status & active_lanes) {
			pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n",
				__func__, lane_status);
		if (lane_status & (active_lanes << 8)) {
			pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n",
				__func__, ctrl_pdata->ndx, lane_status);
			ret = -EINVAL;
			mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
			goto error;
		}

@@ -569,15 +585,15 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		if (ctrl_pdata->ndx == DSI_CTRL_0) {
			regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval | 0x3FF);
				regval | clamp_reg);
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval | 0x83FF);
				regval | (clamp_reg | BIT(15)));
		} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
			regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval | 0x3FF0000);
				regval | (clamp_reg << 16));
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval | 0x83FF0000);
				regval | ((clamp_reg << 16) | BIT(31)));
		}

		wmb();
@@ -588,19 +604,8 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		 * out of power collapse
		 */
		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
		/* disable DSI controller */
		mdss_dsi_controller_cfg(0, pdata);

		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
		ctrl_pdata->ulps = true;
	} else if (ctrl_pdata->ulps) {
		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
		if (ret) {
			pr_err("%s: Failed to enable bus clocks. rc=%d\n",
				__func__, ret);
			goto error;
		}

		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0);
		mdss_dsi_phy_init(pdata);

@@ -617,33 +622,26 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		 * Wait for a short duration to ensure that the lanes
		 * enter ULP state.
		 */
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
		usleep(100);

		/* Disable MMSS DSI Clamps */
		if (ctrl_pdata->ndx == DSI_CTRL_0) {
			regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval & ~0x83FF);
				regval & ~(clamp_reg | BIT(15)));
		} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
			regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
			MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
				regval & ~0x83FF0000);
				regval & ~((clamp_reg << 16) | BIT(31)));
		}

		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1);
		if (ret) {
			pr_err("%s: Failed to enable link clocks. rc=%d\n",
				__func__, ret);
			mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
			goto error;
		}

		/*
		 * ULPS Exit Request
		 * Hardware requirement is to wait for at least 1ms
		 */
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8);
		usleep(1000);
		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);

@@ -654,8 +652,6 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		usleep(100);

		lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0);
		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
		ctrl_pdata->ulps = false;
	}

@@ -691,78 +687,6 @@ static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,

	return ret;
}
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
	int enable)
{
	int rc;
	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
	struct mdss_dsi_ctrl_pdata *sctrl = NULL;

	if (&ctrl->mmss_misc_io == NULL) {
		pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
		return -EINVAL;
	}

	if (mdss_dsi_is_master_ctrl(ctrl)) {
		if (enable) {
			pr_debug("%s: skipping enable for master ctrl%d\n",
				__func__, ctrl->ndx);
			rc = 0;
			goto error;
		} else {
			sctrl = mdss_dsi_get_slave_ctrl();
			if (!sctrl) {
				pr_err("%s: Unable to get slave control\n",
					__func__);
				rc = -EINVAL;
				goto error;
			}
		}
	}

	if (mdss_dsi_is_slave_ctrl(ctrl)) {
		if (enable) {
			mctrl = mdss_dsi_get_master_ctrl();
			if (!mctrl) {
				pr_err("%s: Unable to get master control\n",
					__func__);
				rc = -EINVAL;
				goto error;
			}
		} else {
			pr_debug("%s: skipping disable for slave ctrl%d\n",
				__func__, ctrl->ndx);
			rc = 0;
			goto error;
		}
	}

	if (mctrl) {
		pr_debug("%s: configuring ulps (%s) for master ctrl%d\n",
			__func__, (enable ? "on" : "off"), mctrl->ndx);
		rc = mdss_dsi_ulps_config_sub(mctrl, enable);
		if (rc)
			goto error;
	}

	pr_debug("%s: configuring ulps (%s) for ctrl%d\n",
		__func__, (enable ? "on" : "off"), ctrl->ndx);
	rc = mdss_dsi_ulps_config_sub(ctrl, enable);
	if (rc)
		goto error;

	if (sctrl) {
		pr_debug("%s: configuring ulps (%s) for slave ctrl%d\n",
			__func__, (enable ? "on" : "off"), sctrl->ndx);
		rc = mdss_dsi_ulps_config_sub(sctrl, enable);
	}

error:
	if (rc)
		pr_err("%s: Failed to configure ulps (%s) for ctrl%d\n",
			__func__, (enable ? "on" : "off"), ctrl->ndx);
	return rc;
}

int mdss_dsi_on(struct mdss_panel_data *pdata)
{
@@ -920,13 +844,15 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
				panel_data);
	mipi  = &pdata->panel_info.mipi;

	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);

	if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
		if (!pdata->panel_info.dynamic_switch_pending) {
			ret = ctrl_pdata->on(pdata);
			if (ret) {
				pr_err("%s: unable to initialize the panel\n",
							__func__);
				return ret;
				goto error;
			}
		}
		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
@@ -936,6 +862,8 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
		mipi->vsync_enable && mipi->hw_vsync_mode)
		mdss_dsi_set_tear_on(ctrl_pdata);

error:
	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
	pr_debug("%s-:\n", __func__);

	return ret;
@@ -958,16 +886,7 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata)
				panel_data);
	mipi = &pdata->panel_info.mipi;

	if (__mdss_dsi_ulps_feature_enabled(pdata) &&
		(ctrl_pdata->ulps)) {
		/* Disable ULPS mode before blanking the panel */
		ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
		if (ret) {
			pr_err("%s: failed to exit ULPS mode. rc=%d\n",
				__func__, ret);
			return ret;
		}
	}
	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);

	if (pdata->panel_info.type == MIPI_VIDEO_PANEL &&
			ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) {
@@ -997,12 +916,14 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata)
			ret = ctrl_pdata->off(pdata);
			if (ret) {
				pr_err("%s: Panel OFF failed\n", __func__);
				return ret;
				goto error;
			}
		}
		ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
	}

error:
	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
	pr_debug("%s-:End\n", __func__);
	return ret;
}
@@ -1270,9 +1191,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
	case MDSS_EVENT_DSI_STREAM_SIZE:
		rc = mdss_dsi_set_stream_size(pdata);
		break;
	case MDSS_EVENT_DSI_ULPS_CTRL:
		rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg);
		break;
	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
		rc = mdss_dsi_update_panel_config(ctrl_pdata,
					(int)(unsigned long) arg);
+8 −0
Original line number Diff line number Diff line
@@ -398,6 +398,7 @@ void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable);

int mdss_dsi_panel_init(struct device_node *node,
		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
@@ -468,4 +469,11 @@ static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx)

	return ctrl_list[ndx];
}

static inline bool mdss_dsi_ulps_feature_enabled(
	struct mdss_panel_data *pdata)
{
	return pdata->panel_info.ulps_feature_enabled;
}

#endif /* MDSS_DSI_H */
+25 −33
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#include "mdss_debug.h"
#include "mdss_mdp_trace.h"

#define VSYNC_EXPIRE_TICK 4
#define VSYNC_EXPIRE_TICK 6

#define MAX_SESSIONS 2

@@ -26,7 +26,7 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)

#define STOP_TIMEOUT(hz) msecs_to_jiffies((1000 / hz) * (VSYNC_EXPIRE_TICK + 2))
#define ULPS_ENTER_TIME msecs_to_jiffies(100)
#define POWER_COLLAPSE_TIME msecs_to_jiffies(100)

struct mdss_mdp_cmd_ctx {
	struct mdss_mdp_ctl *ctl;
@@ -43,12 +43,12 @@ struct mdss_mdp_cmd_ctx {
	struct mutex clk_mtx;
	spinlock_t clk_lock;
	struct work_struct clk_work;
	struct delayed_work ulps_work;
	struct delayed_work pc_work;
	struct work_struct pp_done_work;
	atomic_t pp_done_cnt;
	struct mdss_panel_recovery recovery;
	bool ulps;
	struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
	bool idle_pc;
};

struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -195,17 +195,15 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
						ctx->rdptr_enabled);
	if (!ctx->clk_enabled) {
		ctx->clk_enabled = 1;
		if (cancel_delayed_work_sync(&ctx->ulps_work))
			pr_debug("deleted pending ulps work\n");
		if (cancel_delayed_work_sync(&ctx->pc_work))
			pr_debug("deleted pending power collapse work\n");

		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

		if (ctx->ulps) {
		if (ctx->idle_pc) {
			if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl))
				pr_warn("tearcheck setup failed\n");
			mdss_mdp_ctl_intf_event(ctx->ctl,
				MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
			ctx->ulps = false;
			ctx->idle_pc = false;
		}

		mdss_mdp_ctl_intf_event
@@ -241,8 +239,9 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
		mdss_mdp_ctl_intf_event
			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
		if (ctx->panel_on)
			schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
		if ((ctx->panel_on) && (mdata->idle_pc_enabled))
			schedule_delayed_work(&ctx->pc_work,
				POWER_COLLAPSE_TIME);
	}
	mutex_unlock(&ctx->clk_mtx);
}
@@ -388,12 +387,11 @@ static void clk_ctrl_work(struct work_struct *work)
	mdss_mdp_cmd_clk_off(ctx);
}

static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
static void __mdss_mdp_cmd_pc_work(struct work_struct *work)
{
	struct delayed_work *dw = to_delayed_work(work);
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_cmd_ctx *ctx =
		container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
		container_of(dw, struct mdss_mdp_cmd_ctx, pc_work);

	if (!ctx) {
		pr_err("%s: invalid ctx\n", __func__);
@@ -401,19 +399,13 @@ static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
	}

	if (!ctx->panel_on) {
		pr_err("Panel is off. skipping ULPS configuration\n");
		pr_err("Panel is off. skipping power collapse\n");
		return;
	}

	if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
		(void *)1)) {
		ctx->ulps = true;
		if (mdata->idle_pc_enabled) {
	ctx->idle_pc = true;
	ctx->ctl->play_cnt = 0;
			mdss_mdp_footswitch_ctrl_idle_pc(0,
				&ctx->ctl->mfd->pdev->dev);
		}
	}
	mdss_mdp_footswitch_ctrl_idle_pc(0, &ctx->ctl->mfd->pdev->dev);
}

static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
@@ -504,10 +496,10 @@ int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff)

	pdata = ctl->panel_data;

	pdata->panel_info.cont_splash_enabled = 0;

	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);

	pdata->panel_info.cont_splash_enabled = 0;

	return ret;
}

@@ -797,8 +789,8 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
	if (cancel_work_sync(&ctx->clk_work))
		pr_debug("no pending clk work\n");

	if (cancel_delayed_work_sync(&ctx->ulps_work))
		pr_debug("deleted pending ulps work\n");
	if (cancel_delayed_work_sync(&ctx->pc_work))
		pr_debug("deleted pending power collapse work\n");

	ctx->panel_on = 0;
	mdss_mdp_cmd_clk_off(ctx);
@@ -811,9 +803,6 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
				   NULL, NULL);

	memset(ctx, 0, sizeof(*ctx));
	ctl->priv_data = NULL;

	if (ctl->num == 0) {
		ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
		WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
@@ -822,6 +811,9 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
		WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
	}

	memset(ctx, 0, sizeof(*ctx));
	ctl->priv_data = NULL;

	ctl->stop_fnc = NULL;
	ctl->display_fnc = NULL;
	ctl->wait_pingpong = NULL;
@@ -874,7 +866,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
	spin_lock_init(&ctx->clk_lock);
	mutex_init(&ctx->clk_mtx);
	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
	INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
	INIT_DELAYED_WORK(&ctx->pc_work, __mdss_mdp_cmd_pc_work);
	INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
	atomic_set(&ctx->pp_done_cnt, 0);
	INIT_LIST_HEAD(&ctx->vsync_handlers);
+0 −6
Original line number Diff line number Diff line
@@ -135,11 +135,6 @@ struct mdss_panel_recovery {
 * @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
 * @MDSS_EVENT_ENABLE_PARTIAL_ROI: Event to update ROI of the panel.
 * @MDSS_EVENT_DSI_STREAM_SIZE: Event to update DSI controller's stream size
 * @MDSS_EVENT_DSI_ULPS_CTRL:	Event to configure Ultra Lower Power Saving
 *				mode for the DSI data and clock lanes. The
 *				event arguments can have one of these values:
 *				- 0: Disable ULPS mode
 *				- 1: Enable ULPS mode
 * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
 *				based on the dsi mode passed as argument.
 *				- 0: update to video mode
@@ -163,7 +158,6 @@ enum mdss_intf_events {
	MDSS_EVENT_DSI_CMDLIST_KOFF,
	MDSS_EVENT_ENABLE_PARTIAL_ROI,
	MDSS_EVENT_DSI_STREAM_SIZE,
	MDSS_EVENT_DSI_ULPS_CTRL,
	MDSS_EVENT_DSI_DYNAMIC_SWITCH,
};

+116 −40
Original line number Diff line number Diff line
@@ -509,22 +509,37 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
	u8 clk_type, int enable)
{
	int rc = 0;
	struct mdss_panel_data *pdata;

	if (!ctrl) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	pdata = &ctrl->panel_data;

	pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
		ctrl->ndx, clk_type, enable);

	if (enable) {
		if (clk_type & DSI_BUS_CLKS) {
			/* enable mdss gdsc */
			pr_debug("%s: Enable MDP FS\n", __func__);
			rc = msm_dss_enable_vreg(
				ctrl->power_data[DSI_CORE_PM].vreg_config,
				ctrl->power_data[DSI_CORE_PM].num_vreg, 1);
			if (rc) {
				pr_err("%s: failed to enable vregs for %s\n",
					__func__,
					__mdss_dsi_pm_name(DSI_CORE_PM));
				goto error;
			}

			rc = mdss_dsi_bus_clk_start(ctrl);
			if (rc) {
				pr_err("Failed to start bus clocks. rc=%d\n",
					rc);
				goto error;
				goto error_vreg;
			}
		}
		if (clk_type & DSI_LINK_CLKS) {
@@ -532,18 +547,61 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
			if (rc) {
				pr_err("Failed to start link clocks. rc=%d\n",
					rc);
				if (clk_type & DSI_BUS_CLKS)
					mdss_dsi_bus_clk_stop(ctrl);
				goto error;
				goto error_link_clk_start;
			}
			/* Disable ULPS, if enabled */
			if (ctrl->ulps) {
				rc = mdss_dsi_ulps_config(ctrl, 0);
				if (rc) {
					pr_err("Failed to exit ulps. rc=%d\n",
						rc);
					goto error_ulps_exit;
				}
			}
		}
	} else {
		if (clk_type & DSI_LINK_CLKS)
		if (clk_type & DSI_LINK_CLKS) {
			/*
			 * If ULPS feature is enabled, enter ULPS first.
			 * No need to enable ULPS when turning off clocks
			 * while blanking the panel.
			 */
			if ((mdss_dsi_ulps_feature_enabled(pdata)) &&
				(pdata->panel_info.panel_power_on))
				mdss_dsi_ulps_config(ctrl, 1);
			mdss_dsi_link_clk_stop(ctrl);
		if (clk_type & DSI_BUS_CLKS)
		}
		if (clk_type & DSI_BUS_CLKS) {
			mdss_dsi_bus_clk_stop(ctrl);

			/* disable mdss gdsc */
			pr_debug("%s: Disable MDP FS\n", __func__);
			rc = msm_dss_enable_vreg(
				ctrl->power_data[DSI_CORE_PM].vreg_config,
				ctrl->power_data[DSI_CORE_PM].num_vreg, 0);
			if (rc) {
				pr_warn("%s: failed to disable vregs for %s\n",
					__func__,
					__mdss_dsi_pm_name(DSI_CORE_PM));
				rc = 0;
			}
		}
	}

	return rc;

error_ulps_exit:
	mdss_dsi_link_clk_stop(ctrl);
error_link_clk_start:
	if (clk_type & DSI_BUS_CLKS)
		mdss_dsi_bus_clk_stop(ctrl);
error_vreg:
	if ((clk_type & DSI_BUS_CLKS) &&
		(msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config,
			ctrl->power_data[DSI_CORE_PM].num_vreg, 0))) {
		pr_warn("%s: failed to disable vregs for %s\n", __func__,
			__mdss_dsi_pm_name(DSI_CORE_PM));
	}
error:
	return rc;
}
@@ -569,7 +627,8 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
	u8 clk_type, int enable)
{
	int rc = 0;
	int changed = 0, m_changed = 0;
	int link_changed = 0, bus_changed = 0;
	int m_link_changed = 0, m_bus_changed = 0;
	struct mdss_dsi_ctrl_pdata *mctrl = NULL;

	if (!ctrl) {
@@ -588,62 +647,78 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
			pr_warn("%s: Unable to get master control\n", __func__);
	}

	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d",
	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n",
		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
		ctrl->link_clk_cnt);
	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n",
	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n",
		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
		mctrl ? mctrl->link_clk_cnt : -1, enable);

	mutex_lock(&dsi_clk_lock);

	if (clk_type & DSI_BUS_CLKS) {
		changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
		bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
			enable);
		if (changed && mctrl)
			m_changed = __mdss_dsi_update_clk_cnt(
		if (bus_changed && mctrl)
			m_bus_changed = __mdss_dsi_update_clk_cnt(
				&mctrl->bus_clk_cnt, enable);
	}

	if (clk_type & DSI_LINK_CLKS) {
		changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
		link_changed = __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
			enable);
		if (changed && mctrl)
			m_changed += __mdss_dsi_update_clk_cnt(
		if (link_changed && mctrl)
			m_link_changed = __mdss_dsi_update_clk_cnt(
				&mctrl->link_clk_cnt, enable);
	}

	if (changed) {
		if (enable && m_changed) {
			rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
			if (rc) {
				pr_err("Failed to start mctrl clocks. rc=%d\n",
					rc);
	if (!link_changed && !bus_changed)
		goto no_error; /* clk cnts updated, nothing else needed */

	/*
	 * If updating link clock, need to make sure that the bus
	 * clocks are enabled
	 */
	if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) {
		pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
			__func__, mctrl->ndx);
		goto error_mctrl_start;
	}

	if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) {
		pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
			__func__, ctrl->ndx);
		goto error_mctrl_start;
	}

		rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
	if (enable && (m_bus_changed || m_link_changed)) {
		rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
		if (rc) {
			pr_err("Failed to %s ctrl clocks. rc=%d\n",
				(enable ? "start" : "stop"), rc);
			goto error_ctrl;
			pr_err("Failed to start mctrl clocks. rc=%d\n", rc);
			goto error_mctrl_start;
		}
	}

		if (!enable && m_changed) {
	if (!enable && (m_bus_changed || m_link_changed)) {
		rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
		if (rc) {
				pr_err("Failed to stop mctrl clocks. rc=%d\n",
					rc);
			pr_err("Failed to stop mctrl clocks. rc=%d\n", rc);
			goto error_mctrl_stop;
		}
	}
	rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
	if (rc) {
		pr_err("Failed to %s ctrl clocks. rc=%d\n",
			(enable ? "start" : "stop"), rc);
		goto error_ctrl;
	}

	goto no_error;

error_mctrl_stop:
	mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
error_ctrl:
	if (enable && m_changed)
	if (enable && (m_bus_changed || m_link_changed))
		mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
error_mctrl_start:
	if (clk_type & DSI_BUS_CLKS) {
@@ -661,12 +736,13 @@ error_mctrl_start:

no_error:
	mutex_unlock(&dsi_clk_lock);
	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d",
	pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n",
		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
		ctrl->link_clk_cnt, changed);
	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n",
		ctrl->link_clk_cnt, link_changed && bus_changed);
	pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n",
		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
		mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable);
		mctrl ? mctrl->link_clk_cnt : -1,
		m_link_changed && m_bus_changed, enable);

	return rc;
}