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: Jeevan Shriram <jshriram@codeaurora.org>
[abhimany@codeaurora.org: INIT_COMPLETION fixups]
Signed-off-by: Abhimanyu Kapur <abhimany@codeaurora.org>
This commit is contained in:
Jeevan Shriram 2014-08-19 09:33:30 -07:00 committed by David Keitel
parent eb5019c32c
commit 1745ed0ed5
5 changed files with 272 additions and 38 deletions

View file

@ -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;
}
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);
__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;
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;
@ -1648,6 +1754,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)) {

View file

@ -147,6 +147,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)
@ -166,9 +168,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[];
@ -293,6 +302,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;
@ -337,6 +352,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;
@ -406,7 +422,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);
@ -419,6 +438,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);

View file

@ -96,6 +96,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);
@ -1272,6 +1273,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);
reinit_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)
{
@ -1746,5 +1771,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;
}

View file

@ -636,33 +636,13 @@ 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){
== DFPS_IMMEDIATE_PORCH_UPDATE_MODE) {
u32 line_cnt;
unsigned long flags;
if (!ctx->timegen_en) {

View file

@ -418,6 +418,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)
@ -436,6 +508,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;