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

Commit 35e85887 authored by Ritesh Kumar's avatar Ritesh Kumar
Browse files

drm/msm/dsi-staging: Add ULPS support for platforms with legacy dsi phy



This change adds ULPS feature support for ctrl ver 2.3. ULPS entry-exit
can be either through the DSI controller or the DSI PHY depending on
hardware variation. ULPS entry-exit will be requested through DSI
controller only if it is not handled in DSI PHY. This is required as for
some chipset, ulps ops can be present for both DSI controller version
as well as DSI PHY version.

Change-Id: I7ec7bf29ba2d64e2165dde68abad5e3762df0ce5
Signed-off-by: default avatarRitesh Kumar <riteshk@codeaurora.org>
parent 4e8d0acd
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -75,12 +75,12 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
	switch (version) {
	case DSI_CTRL_VERSION_1_4:
		ctrl->ops.setup_lane_map = dsi_ctrl_hw_14_setup_lane_map;
		ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_14_ulps_request;
		ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_14_ulps_exit;
		ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request;
		ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit;
		ctrl->ops.wait_for_lane_idle =
			dsi_ctrl_hw_14_wait_for_lane_idle;
		ctrl->ops.ulps_ops.get_lanes_in_ulps =
			dsi_ctrl_hw_14_get_lanes_in_ulps;
			dsi_ctrl_hw_cmn_get_lanes_in_ulps;
		ctrl->ops.clamp_enable = dsi_ctrl_hw_14_clamp_enable;
		ctrl->ops.clamp_disable = dsi_ctrl_hw_14_clamp_disable;
		ctrl->ops.reg_dump_to_buffer =
@@ -117,9 +117,10 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
			dsi_ctrl_hw_20_wait_for_lane_idle;
		ctrl->ops.reg_dump_to_buffer =
			dsi_ctrl_hw_20_reg_dump_to_buffer;
		ctrl->ops.ulps_ops.ulps_request = NULL;
		ctrl->ops.ulps_ops.ulps_exit = NULL;
		ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL;
		ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request;
		ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit;
		ctrl->ops.ulps_ops.get_lanes_in_ulps =
			dsi_ctrl_hw_cmn_get_lanes_in_ulps;
		ctrl->ops.clamp_enable = NULL;
		ctrl->ops.clamp_disable = NULL;
		ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
@@ -197,6 +198,7 @@ static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy)
	phy->ops.calculate_timing_params =
		dsi_phy_hw_calculate_timing_params;
	phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0;
	phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl;
}

/**
+4 −3
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy);
int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
		u32 *timing_val, u32 size);
void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);

/* Definitions for 10nm PHY hardware driver */
void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy,
@@ -214,9 +215,9 @@ int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl);
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl,
		       struct dsi_lane_map *lane_map);
void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes);
void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes);
u32 dsi_ctrl_hw_14_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes);
void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes);
u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl);

void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl,
				 u32 lanes,
+17 −9
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2018, 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
@@ -108,12 +108,14 @@ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes)
 * Caller should check if lanes are in ULPS mode by calling
 * get_lanes_in_ulps() operation.
 */
void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
{
	u32 reg = 0;

	reg = DSI_R32(ctrl, DSI_LANE_CTRL);

	if (lanes & DSI_CLOCK_LANE)
		reg = BIT(4);
		reg |= BIT(4);
	if (lanes & DSI_DATA_LANE_0)
		reg |= BIT(0);
	if (lanes & DSI_DATA_LANE_1)
@@ -143,12 +145,16 @@ void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
 * Caller should check if lanes are in active mode by calling
 * get_lanes_in_ulps() operation.
 */
void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
{
	u32 reg = 0;
	u32 prev_reg = 0;

	prev_reg = DSI_R32(ctrl, DSI_LANE_CTRL);
	prev_reg &= BIT(24);

	if (lanes & DSI_CLOCK_LANE)
		reg = BIT(12);
		reg |= BIT(12);
	if (lanes & DSI_DATA_LANE_0)
		reg |= BIT(8);
	if (lanes & DSI_DATA_LANE_1)
@@ -162,7 +168,7 @@ void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
	 * ULPS Exit Request
	 * Hardware requirement is to wait for at least 1ms
	 */
	DSI_W32(ctrl, DSI_LANE_CTRL, reg);
	DSI_W32(ctrl, DSI_LANE_CTRL, reg | prev_reg);
	usleep_range(1000, 1010);
	/*
	 * Sometimes when exiting ULPS, it is possible that some DSI
@@ -170,8 +176,10 @@ void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
	 * commands not going through. To avoid this, force the lanes
	 * to be in stop state.
	 */
	DSI_W32(ctrl, DSI_LANE_CTRL, reg << 8);
	DSI_W32(ctrl, DSI_LANE_CTRL, 0x0);
	DSI_W32(ctrl, DSI_LANE_CTRL, (reg << 8) | prev_reg);
	wmb(); /* ensure lanes are put to stop state */
	DSI_W32(ctrl, DSI_LANE_CTRL, 0x0 | prev_reg);
	wmb(); /* ensure lanes are put to stop state */

	pr_debug("[DSI_%d] ULPS exit request for lanes=0x%x\n",
		 ctrl->index, lanes);
@@ -186,7 +194,7 @@ void dsi_ctrl_hw_14_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
 *
 * Return: List of lanes in ULPS state.
 */
u32 dsi_ctrl_hw_14_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl)
u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl)
{
	u32 reg = 0;
	u32 lanes = 0;
+42 −23
Original line number Diff line number Diff line
@@ -1620,7 +1620,6 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
		bool enable)
{
	/* TODO: make checks based on cont. splash */
	int splash_enabled = false;

	pr_debug("checking ulps req validity\n");

@@ -1654,7 +1653,7 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
	 * boot animation since it is expected that the clocks would be turned
	 * right back on.
	 */
	if (enable && splash_enabled)
	if (enable && display->is_cont_splash_enabled)
		return false;

	return true;
@@ -1689,40 +1688,60 @@ static int dsi_display_set_ulps(struct dsi_display *display, bool enable)
	}

	m_ctrl = &display->ctrl[display->cmd_master_idx];

	rc = dsi_ctrl_set_ulps(m_ctrl->ctrl, enable);
	if (rc) {
		pr_err("Ulps controller state change(%d) failed\n", enable);
		return rc;
	}
	/*
	 * ULPS entry-exit can be either through the DSI controller or
	 * the DSI PHY depending on hardware variation. For some chipsets,
	 * both controller version and phy version ulps entry-exit ops can
	 * be present. To handle such cases, send ulps request through PHY,
	 * if ulps request is handled in PHY, then no need to send request
	 * through controller.
	 */

	rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable,
			display->clamp_enabled);
	if (rc) {

	if (rc == DSI_PHY_ULPS_ERROR) {
		pr_err("Ulps PHY state change(%d) failed\n", enable);
		return rc;
		return -EINVAL;
	}

	else if (rc == DSI_PHY_ULPS_HANDLED) {
		display_for_each_ctrl(i, display) {
			ctrl = &display->ctrl[i];
			if (!ctrl->ctrl || (ctrl == m_ctrl))
				continue;

		rc = dsi_ctrl_set_ulps(ctrl->ctrl, enable);
			rc = dsi_phy_set_ulps(ctrl->phy, &display->config,
					enable, display->clamp_enabled);
			if (rc == DSI_PHY_ULPS_ERROR) {
				pr_err("Ulps PHY state change(%d) failed\n",
						enable);
				return -EINVAL;
			}
		}
	}

	else if (rc == DSI_PHY_ULPS_NOT_HANDLED) {
		rc = dsi_ctrl_set_ulps(m_ctrl->ctrl, enable);
		if (rc) {
			pr_err("Ulps controller state change(%d) failed\n",
					enable);
			return rc;
		}
		display_for_each_ctrl(i, display) {
			ctrl = &display->ctrl[i];
			if (!ctrl->ctrl || (ctrl == m_ctrl))
				continue;

		rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable,
					display->clamp_enabled);
			rc = dsi_ctrl_set_ulps(ctrl->ctrl, enable);
			if (rc) {
			pr_err("Ulps PHY state change(%d) failed\n", enable);
				pr_err("Ulps controller state change(%d) failed\n",
						enable);
				return rc;
			}

		}
	}

	display->ulps_enabled = enable;
	return 0;
}
+9 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2018, 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
@@ -33,6 +33,14 @@
		writel_relaxed((val), (dsi_hw)->mmss_misc_base + (off)); \
	} while (0)

#define DSI_MISC_R32(dsi_hw, off) \
	readl_relaxed((dsi_hw)->phy_clamp_base + (off))
#define DSI_MISC_W32(dsi_hw, off, val) \
	do {\
		pr_debug("[DSI_%d][%s] - [0x%08x]\n", \
			(dsi_hw)->index, #off, val); \
		writel_relaxed((val), (dsi_hw)->phy_clamp_base + (off)); \
	} while (0)
#define DSI_DISP_CC_R32(dsi_hw, off) \
	readl_relaxed((dsi_hw)->disp_cc_base + (off))
#define DSI_DISP_CC_W32(dsi_hw, off, val) \
Loading