From 1745ed0ed555f35cd970243739c4ce50497d2399 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Tue, 19 Aug 2014 09:33:30 -0700 Subject: [PATCH] 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 [abhimany@codeaurora.org: INIT_COMPLETION fixups] Signed-off-by: Abhimanyu Kapur --- drivers/video/fbdev/msm/mdss_dsi.c | 148 ++++++++++++++++-- drivers/video/fbdev/msm/mdss_dsi.h | 20 +++ drivers/video/fbdev/msm/mdss_dsi_host.c | 32 ++++ drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 22 +-- drivers/video/fbdev/msm/msm_mdss_io_8974.c | 88 +++++++++++ 5 files changed, 272 insertions(+), 38 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 2026b5faa55c..8e34460dc280 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -22,12 +22,15 @@ #include #include #include +#include #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)) { diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index e87dd7d9cafc..6c38210d606f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -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); diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 768f07008815..80a5d193cfeb 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -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; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index fe359793986e..da6dd0e1179d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -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) { diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 405a1924acd3..dee32aa4de94 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -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;