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

Commit 5c48065a authored by Jeevan Shriram's avatar Jeevan Shriram Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: Add support for dynamic refresh rate



Add support for dynamic refresh rate through
immediate clock update and dynamic refresh pll
register configuration.

Change-Id: I3ea8da3db100b6e5f21697a80f7b97543d4689f1
Signed-off-by: default avatarJeevan Shriram <jshriram@codeaurora.org>
parent 25d92bd3
Loading
Loading
Loading
Loading
+131 −17
Original line number Diff line number Diff line
@@ -22,12 +22,15 @@
#include <linux/err.h>
#include <linux/regulator/consumer.h>
#include <linux/leds-qpnp-wled.h>
#include <linux/clk.h>

#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_dsi.h"
#include "mdss_debug.h"

#define XO_CLK_RATE	19200000

static int mdss_dsi_pinctrl_set_state(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
					bool active);

@@ -850,12 +853,77 @@ static void __mdss_dsi_update_video_mode_total(struct mdss_panel_data *pdata,

}

static void __mdss_dsi_dyn_refresh_config(
		struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
	int reg_data;

	reg_data = MIPI_INP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL);
	reg_data &= ~BIT(12);

	pr_debug("Dynamic fps ctrl = 0x%x\n", reg_data);
	MIPI_OUTP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL, reg_data);
}

static void __mdss_dsi_calc_dfps_delay(struct mdss_panel_data *pdata)
{
	u32 esc_clk_rate = XO_CLK_RATE;
	u32 pipe_delay, pipe_delay2 = 0, pll_delay;
	u32 hsync_period = 0;
	u32 pclk_to_esc_ratio, byte_to_esc_ratio, hr_bit_to_esc_ratio;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_panel_info *pinfo = NULL;
	struct mdss_dsi_phy_ctrl *pd = NULL;

	if (pdata == NULL) {
		pr_err("%s Invalid pdata\n", __func__);
		return;
	}

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
			panel_data);

	pinfo = &pdata->panel_info;
	pd = &(pinfo->mipi.dsi_phy_db);

	pclk_to_esc_ratio = (ctrl_pdata->pclk_rate / esc_clk_rate);
	byte_to_esc_ratio = (ctrl_pdata->byte_clk_rate / esc_clk_rate);
	hr_bit_to_esc_ratio = ((ctrl_pdata->byte_clk_rate * 4) / esc_clk_rate);

	hsync_period = mdss_panel_get_htotal(pinfo, true);
	pipe_delay = (hsync_period + 1) / pclk_to_esc_ratio;
	if (pinfo->mipi.eof_bllp_power_stop == 0)
		pipe_delay += (17 / pclk_to_esc_ratio) +
			((21 + pinfo->mipi.t_clk_pre +
			pinfo->mipi.t_clk_post) / byte_to_esc_ratio) +
			((((pd->timing[8] >> 1) + 1) +
			((pd->timing[6] >> 1) + 1) +
			((pd->timing[3] * 4) + (pd->timing[5] >> 1) + 1) +
			((pd->timing[7] >> 1) + 1) +
			((pd->timing[1] >> 1) + 1) +
			((pd->timing[4] >> 1) + 1)) / hr_bit_to_esc_ratio);

	if (pinfo->mipi.force_clk_lane_hs)
		pipe_delay2 = (6 / byte_to_esc_ratio) +
			((((pd->timing[1] >> 1) + 1) +
			((pd->timing[4] >> 1) + 1)) / hr_bit_to_esc_ratio);

	pll_delay = ((1000 * esc_clk_rate) / 1000000) * 2;

	MIPI_OUTP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_PIPE_DELAY,
						pipe_delay);
	MIPI_OUTP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_PIPE_DELAY2,
						pipe_delay2);
	MIPI_OUTP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_PLL_DELAY,
						pll_delay);
}

static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
		int new_fps)
{
	int rc = 0;
	u32 data;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	u32 dsi_ctrl;

	if (pdata == NULL) {
		pr_err("%s Invalid pdata\n", __func__);
@@ -876,25 +944,63 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
				__func__);
		return rc;
	}

	if (pdata->panel_info.dfps_update
			== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {

		__mdss_dsi_dyn_refresh_config(ctrl_pdata);
		__mdss_dsi_calc_dfps_delay(pdata);
		ctrl_pdata->pclk_rate =
			pdata->panel_info.mipi.dsi_pclk_rate;
		ctrl_pdata->byte_clk_rate =
			pdata->panel_info.clk_rate / 8;

	if (pdata->panel_info.dfps_update
			== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
		dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
				0x0004);
		pdata->panel_info.mipi.frame_rate = new_fps;
		dsi_ctrl &= ~0x2;
		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
				dsi_ctrl);
		mdss_dsi_controller_cfg(true, pdata);
		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
		dsi_ctrl |= 0x2;
		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
				dsi_ctrl);
		pr_debug("byte_rate=%i\n", ctrl_pdata->byte_clk_rate);
		pr_debug("pclk_rate=%i\n", ctrl_pdata->pclk_rate);

		/* add an extra reference to main clks */
		clk_prepare_enable(ctrl_pdata->pll_byte_clk);
		clk_prepare_enable(ctrl_pdata->pll_pixel_clk);

		/* change the parent to shadow clocks*/
		clk_set_parent(ctrl_pdata->mux_byte_clk,
				ctrl_pdata->shadow_byte_clk);
		clk_set_parent(ctrl_pdata->mux_pixel_clk,
				ctrl_pdata->shadow_pixel_clk);

		rc =  clk_set_rate(ctrl_pdata->byte_clk,
					ctrl_pdata->byte_clk_rate);
		if (rc) {
			pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
					__func__);
			return rc;
		}

		rc = clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate);
		if (rc) {
			pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
				__func__);
			return rc;
		}

		mdss_dsi_en_wait4dynamic_done(ctrl_pdata);
		MIPI_OUTP((ctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL,
							0x00);

		data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0120);
		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x120, data);
		pr_debug("pll unlock: 0x%x\n", data);
		clk_set_parent(ctrl_pdata->mux_byte_clk,
				ctrl_pdata->pll_byte_clk);
		clk_set_parent(ctrl_pdata->mux_pixel_clk,
				ctrl_pdata->pll_pixel_clk);
		clk_disable_unprepare(ctrl_pdata->pll_byte_clk);
		clk_disable_unprepare(ctrl_pdata->pll_pixel_clk);
	} else {
		ctrl_pdata->pclk_rate =
			pdata->panel_info.mipi.dsi_pclk_rate;
		ctrl_pdata->byte_clk_rate =
			pdata->panel_info.clk_rate / 8;
	}

	return rc;
@@ -1660,6 +1766,14 @@ int dsi_panel_device_register(struct device_node *pan_node,
		return -EPERM;
	}

	if (pinfo->dynamic_fps &&
			pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
		if (mdss_dsi_shadow_clk_init(ctrl_pdev, ctrl_pdata)) {
			pr_err("unable to initialize shadow ctrl clks\n");
			return -EPERM;
		}
	}

	if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
					     pinfo->pdest,
					     ctrl_pdata)) {
+20 −0
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ enum dsi_pm_type {
#define DSI_CMD_DST_FORMAT_RGB666	7
#define DSI_CMD_DST_FORMAT_RGB888	8

#define DSI_INTR_DYNAMIC_REFRESH_MASK		BIT(29)
#define DSI_INTR_DYNAMIC_REFRESH_DONE		BIT(28)
#define DSI_INTR_ERROR_MASK		BIT(25)
#define DSI_INTR_ERROR			BIT(24)
#define DSI_INTR_BTA_DONE_MASK          BIT(21)
@@ -167,9 +169,16 @@ enum dsi_pm_type {

#define DSI_VIDEO_TERM  BIT(16)
#define DSI_MDP_TERM    BIT(8)
#define DSI_DYNAMIC_TERM    BIT(4)
#define DSI_BTA_TERM    BIT(1)
#define DSI_CMD_TERM    BIT(0)

/* offsets for dynamic refresh */
#define DSI_DYNAMIC_REFRESH_CTRL		0x200
#define DSI_DYNAMIC_REFRESH_PIPE_DELAY		0x204
#define DSI_DYNAMIC_REFRESH_PIPE_DELAY2		0x208
#define DSI_DYNAMIC_REFRESH_PLL_DELAY		0x20C

extern struct device dsi_dev;
extern u32 dsi_irq;
extern struct mdss_dsi_ctrl_pdata *ctrl_list[];
@@ -292,6 +301,12 @@ struct mdss_dsi_ctrl_pdata {
	struct clk *byte_clk;
	struct clk *esc_clk;
	struct clk *pixel_clk;
	struct clk *mux_byte_clk;
	struct clk *mux_pixel_clk;
	struct clk *pll_byte_clk;
	struct clk *pll_pixel_clk;
	struct clk *shadow_byte_clk;
	struct clk *shadow_pixel_clk;
	u8 ctrl_state;
	int panel_mode;
	int irq_cnt;
@@ -335,6 +350,7 @@ struct mdss_dsi_ctrl_pdata {
	struct completion dma_comp;
	struct completion mdp_comp;
	struct completion video_comp;
	struct completion dynamic_comp;
	struct completion bta_comp;
	spinlock_t irq_lock;
	spinlock_t mdp_lock;
@@ -403,7 +419,10 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
			    int frame_rate);
int mdss_dsi_clk_init(struct platform_device *pdev,
		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_shadow_clk_init(struct platform_device *pdev,
		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_shadow_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
@@ -416,6 +435,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev,
			struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_en_wait4dynamic_done(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
+32 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev,
	init_completion(&ctrl->dma_comp);
	init_completion(&ctrl->mdp_comp);
	init_completion(&ctrl->video_comp);
	init_completion(&ctrl->dynamic_comp);
	init_completion(&ctrl->bta_comp);
	spin_lock_init(&ctrl->irq_lock);
	spin_lock_init(&ctrl->mdp_lock);
@@ -1260,6 +1261,30 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
	return rx_byte;
}

void mdss_dsi_en_wait4dynamic_done(struct mdss_dsi_ctrl_pdata *ctrl)
{
	unsigned long flag;
	u32 data;
	/* DSI_INTL_CTRL */
	data = MIPI_INP((ctrl->ctrl_base) + 0x0110);
	data |= DSI_INTR_DYNAMIC_REFRESH_MASK;
	MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);

	spin_lock_irqsave(&ctrl->mdp_lock, flag);
	INIT_COMPLETION(ctrl->dynamic_comp);
	mdss_dsi_enable_irq(ctrl, DSI_DYNAMIC_TERM);
	spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
	MIPI_OUTP((ctrl->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL,
			(BIT(8) | BIT(0)));

	if (!wait_for_completion_timeout(&ctrl->dynamic_comp,
				msecs_to_jiffies(VSYNC_PERIOD * 4)))
		pr_err("Dynamic interrupt timedout\n");

	data = MIPI_INP((ctrl->ctrl_base) + 0x0110);
	data &= ~DSI_INTR_DYNAMIC_REFRESH_MASK;
	MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);
}

void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
{
@@ -1724,5 +1749,12 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr)
		spin_unlock(&ctrl->mdp_lock);
	}

	if (isr & DSI_INTR_DYNAMIC_REFRESH_DONE) {
		spin_lock(&ctrl->mdp_lock);
		mdss_dsi_disable_irq_nosync(ctrl, DSI_DYNAMIC_TERM);
		complete(&ctrl->dynamic_comp);
		spin_unlock(&ctrl->mdp_lock);
	}

	return IRQ_HANDLED;
}
+1 −21
Original line number Diff line number Diff line
@@ -636,31 +636,11 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
				pr_err("TG is OFF. DFPS mode invalid\n");
				return -EINVAL;
			}
			ctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK;
			mdss_mdp_display_commit(ctl, NULL, NULL);
			mdss_mdp_display_wait4comp(ctl);
			mdp_video_write(ctx,
					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
			/*
			 * Need to wait for atleast one vsync time for proper
			 * TG OFF before doing changes on interfaces
			 */
			msleep(20);
			rc = mdss_mdp_ctl_intf_event(ctl,
					MDSS_EVENT_PANEL_UPDATE_FPS,
					(void *) (unsigned long) new_fps);
			WARN(rc, "intf %d panel fps update error (%d)\n",
							ctl->intf_num, rc);
			mdp_video_write(ctx,
					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
			/*
			 * Add memory barrier to make sure the MDP Video
			 * mode engine is enabled before next frame is sent
			 */
			mb();
			ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
			mdss_mdp_display_commit(ctl, NULL, NULL);
			mdss_mdp_display_wait4comp(ctl);
		} else if (pdata->panel_info.dfps_update
				== DFPS_IMMEDIATE_PORCH_UPDATE_MODE) {
			u32 line_cnt;
+88 −0
Original line number Diff line number Diff line
@@ -408,6 +408,78 @@ mdss_dsi_clk_err:
	return rc;
}

int mdss_dsi_shadow_clk_init(struct platform_device *pdev,
		struct mdss_dsi_ctrl_pdata *ctrl)
{
	struct device *dev = NULL;
	int rc = 0;

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

	dev = &pdev->dev;
	ctrl->mux_byte_clk = clk_get(dev, "mdss_byte_clk_mux");
	if (IS_ERR(ctrl->mux_byte_clk)) {
		rc = PTR_ERR(ctrl->mux_byte_clk);
		pr_err("%s: can't find mux_byte_clk. rc=%d\n",
			__func__, rc);
		ctrl->mux_byte_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

	ctrl->mux_pixel_clk = clk_get(dev, "mdss_pixel_clk_mux");
	if (IS_ERR(ctrl->mux_pixel_clk)) {
		rc = PTR_ERR(ctrl->mux_pixel_clk);
		pr_err("%s: can't find mdss_mux_pixel_clk. rc=%d\n",
			__func__, rc);
		ctrl->mux_pixel_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

	ctrl->pll_byte_clk = clk_get(dev, "byte_clk_src");
	if (IS_ERR(ctrl->pll_byte_clk)) {
		rc = PTR_ERR(ctrl->pll_byte_clk);
		pr_err("%s: can't find pll_byte_clk. rc=%d\n",
			__func__, rc);
		ctrl->pll_byte_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

	ctrl->pll_pixel_clk = clk_get(dev, "pixel_clk_src");
	if (IS_ERR(ctrl->pll_pixel_clk)) {
		rc = PTR_ERR(ctrl->pll_pixel_clk);
		pr_err("%s: can't find pll_pixel_clk. rc=%d\n",
			__func__, rc);
		ctrl->pll_pixel_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

	ctrl->shadow_byte_clk = clk_get(dev, "shadow_byte_clk_src");
	if (IS_ERR(ctrl->shadow_byte_clk)) {
		rc = PTR_ERR(ctrl->shadow_byte_clk);
		pr_err("%s: can't find shadow_byte_clk. rc=%d\n",
			__func__, rc);
		ctrl->shadow_byte_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

	ctrl->shadow_pixel_clk = clk_get(dev, "shadow_pixel_clk_src");
	if (IS_ERR(ctrl->shadow_pixel_clk)) {
		rc = PTR_ERR(ctrl->shadow_pixel_clk);
		pr_err("%s: can't find shadow_pixel_clk. rc=%d\n",
			__func__, rc);
		ctrl->shadow_pixel_clk = NULL;
		goto mdss_dsi_shadow_clk_err;
	}

mdss_dsi_shadow_clk_err:
	if (rc)
		mdss_dsi_shadow_clk_deinit(ctrl);
	return rc;
}

void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata  *ctrl)
{
	if (ctrl->byte_clk)
@@ -426,6 +498,22 @@ void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl)
		clk_put(ctrl->mdp_core_clk);
}

void mdss_dsi_shadow_clk_deinit(struct mdss_dsi_ctrl_pdata  *ctrl)
{
	if (ctrl->mux_byte_clk)
		clk_put(ctrl->mux_byte_clk);
	if (ctrl->mux_pixel_clk)
		clk_put(ctrl->mux_pixel_clk);
	if (ctrl->pll_byte_clk)
		clk_put(ctrl->pll_byte_clk);
	if (ctrl->pll_pixel_clk)
		clk_put(ctrl->pll_pixel_clk);
	if (ctrl->shadow_byte_clk)
		clk_put(ctrl->shadow_byte_clk);
	if (ctrl->shadow_pixel_clk)
		clk_put(ctrl->shadow_pixel_clk);
}

#define PREF_DIV_RATIO 27
struct dsiphy_pll_divider_config pll_divider_config;