diff options
| author | Chandan Uddaraju <chandanu@codeaurora.org> | 2013-03-26 14:10:40 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:15:42 -0700 |
| commit | e1095524a09054d022e15c5e63574d1ef3f5cc66 (patch) | |
| tree | 4d040c6e97fc95d57134a43745d2ad9907d82e8b /drivers/video/fbdev | |
| parent | 4e3d5715cff9c832fc3066a7a8196f9078845f45 (diff) | |
mdss: display: add dsi command mode panel support
Add changes to support TE signal needed for smart panels.
The panel backlight is controlled using pwm.
Change-Id: Id596b466b6fd16efbb26ffcc35db94c9939007b0
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
[cip@codeaurora.org: Moved mdss_mdp_intf_cmd.c file location]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 198 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 17 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_host.c | 154 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_panel.c | 201 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_edp.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 9 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 335 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 6 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_util.c | 18 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_panel.h | 26 |
13 files changed, 751 insertions, 221 deletions
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index 4513f656d994..e213442a657c 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -3,6 +3,7 @@ ccflags-y := -Idrivers/staging/android mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o mdss-mdp-objs += mdss_mdp_pp.o mdss-mdp-objs += mdss_mdp_intf_video.o +mdss-mdp-objs += mdss_mdp_intf_cmd.o mdss-mdp-objs += mdss_mdp_intf_writeback.o mdss-mdp-objs += mdss_mdp_rotator.o mdss-mdp-objs += mdss_mdp_overlay.o diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 62fb46b5a42e..7d03d635156e 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -25,6 +25,7 @@ #include "mdss.h" #include "mdss_panel.h" #include "mdss_dsi.h" +#include "mdss_debug.h" static unsigned char *mdss_dsi_base; @@ -250,32 +251,6 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable) return 0; } -static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata) -{ - struct mdss_panel_info *pinfo; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - int ret = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - pinfo = &pdata->panel_info; - - mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); - - ret = ctrl_pdata->off(pdata); - if (ret) { - pr_err("%s: Panel OFF failed\n", __func__); - return ret; - } - - return ret; -} - static void mdss_dsi_put_dt_vreg_data(struct device *dev, struct dss_module_power *module_power) { @@ -443,6 +418,10 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + + pr_debug("%s+: ctrl=%p ndx=%d\n", __func__, + ctrl_pdata, ctrl_pdata->ndx); + mdss_dsi_clk_disable(pdata); mdss_dsi_unprepare_clocks(ctrl_pdata); @@ -514,6 +493,10 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + + pr_debug("%s+: ctrl=%p ndx=%d\n", + __func__, ctrl_pdata, ctrl_pdata->ndx); + pinfo = &pdata->panel_info; ret = mdss_dsi_panel_power_on(pdata, 1); @@ -597,6 +580,27 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) wmb(); } + pr_debug("%s-:\n", __func__); + return 0; +} + +static int mdss_dsi_unblank(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct mipi_panel_info *mipi; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + pr_debug("%s+:\n", __func__); + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + mipi = &pdata->panel_info.mipi; + ret = ctrl_pdata->on(pdata); if (ret) { pr_err("%s: unable to initialize the panel\n", __func__); @@ -605,6 +609,34 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) mdss_dsi_op_mode_config(mipi->mode, pdata); + pr_debug("%s-:\n", __func__); + + return ret; +} + +static int mdss_dsi_blank(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + pr_debug("%s+:\n", __func__); + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); + + ret = ctrl_pdata->off(pdata); + if (ret) { + pr_err("%s: Panel OFF failed\n", __func__); + return ret; + } + pr_debug("%s-:End\n", __func__); return ret; } @@ -621,33 +653,27 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + pr_debug("%s+:event=%d\n", __func__, event); + switch (event) { case MDSS_EVENT_UNBLANK: + rc = mdss_dsi_on(pdata); if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) { - rc = mdss_dsi_on(pdata); - } else { - pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n", - __func__, event, - ctrl_pdata->on_cmds->ctrl_state); - rc = -EINVAL; + rc = mdss_dsi_unblank(pdata); } break; + case MDSS_EVENT_PANEL_ON: + if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE) + rc = mdss_dsi_unblank(pdata); + break; case MDSS_EVENT_BLANK: if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) { - rc = mdss_dsi_ctrl_unprepare(pdata); - } else { - pr_debug("%s:event=%d,Unprepare not called.Ctrl_state: %d\n", - __func__, event, - ctrl_pdata->on_cmds->ctrl_state); - rc = -EINVAL; + rc = mdss_dsi_blank(pdata); } break; - case MDSS_EVENT_TIMEGEN_OFF: + case MDSS_EVENT_PANEL_OFF: if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) { - pr_debug("%s:event=%d, calling unprepare: ctrl_state: %d\n", - __func__, event, - ctrl_pdata->on_cmds->ctrl_state); - rc = mdss_dsi_ctrl_unprepare(pdata); + rc = mdss_dsi_blank(pdata); } rc = mdss_dsi_off(pdata); break; @@ -665,6 +691,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, pr_debug("%s: unhandled event=%d\n", __func__, event); break; } + pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); return rc; } @@ -674,8 +701,6 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) u32 index; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - pr_debug("%s\n", __func__); - if (pdev->dev.of_node) { struct resource *mdss_dsi_mres; const char *ctrl_name; @@ -789,7 +814,7 @@ static int mdss_dsi_ctrl_remove(struct platform_device *pdev) struct device dsi_dev; int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode, - unsigned char **ctrl_base) + struct mdss_dsi_ctrl_pdata *ctrl) { int rc = 0; u32 index; @@ -828,21 +853,25 @@ int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode, return -ENOMEM; } - *ctrl_base = ioremap(mdss_dsi_mres->start, + ctrl->ctrl_base = ioremap(mdss_dsi_mres->start, resource_size(mdss_dsi_mres)); - if (!(*ctrl_base)) { + if (!(ctrl->ctrl_base)) { pr_err("%s:%d unable to remap dsi resources", __func__, __LINE__); return -ENOMEM; } + ctrl->reg_size = resource_size(mdss_dsi_mres); + + pr_info("%s: dsi base=%x size=%x\n", + __func__, (int)ctrl->ctrl_base, ctrl->reg_size); + return 0; } int dsi_panel_device_register(struct platform_device *pdev, - struct mdss_panel_common_pdata *panel_data, - char backlight_ctrl) + struct mdss_panel_common_pdata *panel_data) { struct mipi_panel_info *mipi; int rc; @@ -851,7 +880,6 @@ int dsi_panel_device_register(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata; struct device_node *dsi_ctrl_np = NULL; struct platform_device *ctrl_pdev = NULL; - unsigned char *ctrl_addr; bool broadcast; bool cont_splash_enabled = false; @@ -891,8 +919,7 @@ int dsi_panel_device_register(struct platform_device *pdev, else bpp = 3; /* Default format set to RGB888 */ - if (panel_data->panel_info.type == MIPI_VIDEO_PANEL && - !panel_data->panel_info.clk_rate) { + if (!panel_data->panel_info.clk_rate) { h_period += panel_data->panel_info.lcdc.xres_pad; v_period += panel_data->panel_info.lcdc.yres_pad; @@ -961,6 +988,45 @@ int dsi_panel_device_register(struct platform_device *pdev, } } + ctrl_pdata->disp_te_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,te-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) { + pr_err("%s:%d, Disp_te gpio not specified\n", + __func__, __LINE__); + } else { + rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te"); + if (rc) { + pr_err("request TE gpio failed, rc=%d\n", + rc); + gpio_free(ctrl_pdata->disp_te_gpio); + return -ENODEV; + } + rc = gpio_tlmm_config(GPIO_CFG( + ctrl_pdata->disp_te_gpio, 1, + GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, + GPIO_CFG_2MA), + GPIO_CFG_ENABLE); + + if (rc) { + pr_err("%s: unable to config tlmm = %d\n", + __func__, ctrl_pdata->disp_te_gpio); + gpio_free(ctrl_pdata->disp_te_gpio); + return -ENODEV; + } + + rc = gpio_direction_input(ctrl_pdata->disp_te_gpio); + if (rc) { + pr_err("set_direction for disp_en gpio failed, rc=%d\n", + rc); + gpio_free(ctrl_pdata->disp_te_gpio); + return -ENODEV; + } + pr_debug("%s: te_gpio=%d\n", __func__, + ctrl_pdata->disp_te_gpio); + } + + ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,rst-gpio", 0); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { @@ -985,12 +1051,11 @@ int dsi_panel_device_register(struct platform_device *pdev, if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev, panel_data->panel_info.pdest, - &ctrl_addr)) { + ctrl_pdata)) { pr_err("%s: unable to get Dsi controller res\n", __func__); return -EPERM; } - pr_debug("%s: ctrl base address: 0x%x\n", __func__, (int)ctrl_addr); ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler; ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds; @@ -1001,9 +1066,16 @@ int dsi_panel_device_register(struct platform_device *pdev, sizeof(struct mdss_panel_info)); mdss_dsi_irq_handler_config(ctrl_pdata); - (ctrl_pdata->panel_data).set_backlight = panel_data->bl_fnc; - (ctrl_pdata->ctrl_base) = ctrl_addr; - (ctrl_pdata->bl_ctrl) = backlight_ctrl; + ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc; + ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl; + ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio; + ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period; + ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan; + ctrl_pdata->bklt_max = panel_data->panel_info.bl_max; + + if (ctrl_pdata->bklt_ctrl == BL_PWM) + mdss_dsi_panel_pwm_cfg(ctrl_pdata); + /* * register in mdp driver */ @@ -1047,6 +1119,16 @@ int dsi_panel_device_register(struct platform_device *pdev, pr_debug("%s: pclk=%d, bclk=%d\n", __func__, ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate); + if (panel_data->panel_info.pdest == DISPLAY_1) { + mdss_debug_register_base("dsi0", + ctrl_pdata->ctrl_base, ctrl_pdata->reg_size); + ctrl_pdata->ndx = 0; + } else { + mdss_debug_register_base("dsi1", + ctrl_pdata->ctrl_base, ctrl_pdata->reg_size); + ctrl_pdata->ndx = 1; + } + pr_debug("%s: Panal data initialized\n", __func__); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index b365f36d90b8..197ff7a2790b 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -273,17 +273,27 @@ struct dsi_drv_cm_data { }; struct mdss_dsi_ctrl_pdata { + int ndx; int (*on) (struct mdss_panel_data *pdata); int (*off) (struct mdss_panel_data *pdata); struct mdss_panel_data panel_data; + struct mdss_hw *mdss_hw; unsigned char *ctrl_base; - char bl_ctrl; + int reg_size; struct clk *byte_clk; struct clk *esc_clk; struct clk *pixel_clk; + int irq_cnt; int mdss_dsi_clk_on; int rst_gpio; int disp_en_gpio; + int disp_te_gpio; + int bklt_ctrl; /* backlight ctrl */ + int pwm_period; + int pwm_gpio; + int pwm_lpg_chan; + int bklt_max; + struct pwm_device *pwm_bl; struct dsi_panel_cmds_list *on_cmds; struct dsi_panel_cmds_list *off_cmds; struct dsi_drv_cm_data shared_pdata; @@ -293,8 +303,7 @@ struct mdss_dsi_ctrl_pdata { }; int dsi_panel_device_register(struct platform_device *pdev, - struct mdss_panel_common_pdata *panel_data, - char bl_ctrl); + struct mdss_panel_common_pdata *panel_data); char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen); char *mdss_dsi_buf_init(struct dsi_buf *dp); @@ -343,5 +352,7 @@ void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable); void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on); void mdss_dsi_phy_init(struct mdss_panel_data *pdata); void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base); +void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata); +void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl); #endif /* MDSS_DSI_H */ diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 6f7023c745df..ccec0fc8bd34 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -26,7 +26,6 @@ #include "mdss_dsi.h" static struct completion dsi_dma_comp; -static int dsi_irq_enabled; static spinlock_t dsi_irq_lock; static spinlock_t dsi_mdp_lock; static int dsi_mdp_busy; @@ -51,91 +50,48 @@ void mdss_dsi_init(void) spin_lock_init(&dsi_mdp_lock); } -void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl) { - if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1) - mdss_dsi0_hw.ptr = (void *)(ctrl_pdata); - else - mdss_dsi1_hw.ptr = (void *)(ctrl_pdata); -} - -void mdss_dsi_enable_irq(struct mdss_panel_data *pdata) -{ - unsigned long flags; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - spin_lock_irqsave(&dsi_irq_lock, flags); - if (dsi_irq_enabled) { - pr_debug("%s: IRQ aleady enabled\n", __func__); - spin_unlock_irqrestore(&dsi_irq_lock, flags); - return; + if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) { + mdss_dsi0_hw.ptr = (void *)(ctrl); + ctrl->mdss_hw = &mdss_dsi0_hw; + } else { + mdss_dsi1_hw.ptr = (void *)(ctrl); + ctrl->mdss_hw = &mdss_dsi1_hw; } - - if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) - mdss_enable_irq(&mdss_dsi0_hw); - else - mdss_enable_irq(&mdss_dsi1_hw); - - dsi_irq_enabled = 1; - /* TO DO: Check whether MDSS IRQ is enabled */ - spin_unlock_irqrestore(&dsi_irq_lock, flags); } -void mdss_dsi_disable_irq(struct mdss_panel_data *pdata) +void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr) { unsigned long flags; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); + if (ctrl == NULL) { + pr_err("%s: Invalid ctrl\n", __func__); return; } - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - spin_lock_irqsave(&dsi_irq_lock, flags); - if (dsi_irq_enabled == 0) { - pr_debug("%s: IRQ already disabled\n", __func__); - spin_unlock_irqrestore(&dsi_irq_lock, flags); - return; + if (enable) { + if (ctrl->irq_cnt == 0) + mdss_enable_irq(ctrl->mdss_hw); + ctrl->irq_cnt++; + } else { + if (ctrl->irq_cnt) { + ctrl->irq_cnt--; + if (ctrl->irq_cnt == 0) { + if (isr) + mdss_disable_irq_nosync(ctrl->mdss_hw); + else + mdss_disable_irq(ctrl->mdss_hw); + } + } } - if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1) - mdss_disable_irq(&mdss_dsi0_hw); - else - mdss_disable_irq(&mdss_dsi1_hw); - - dsi_irq_enabled = 0; - /* TO DO: Check whether MDSS IRQ is Disabled */ + pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__, + ctrl->ndx, enable, ctrl->irq_cnt); spin_unlock_irqrestore(&dsi_irq_lock, flags); } /* - * mdss_dsi_disale_irq_nosync() should be called - * from interrupt context - */ -void mdss_dsi_disable_irq_nosync(void) -{ - spin_lock(&dsi_irq_lock); - if (dsi_irq_enabled == 0) { - pr_debug("%s: IRQ cannot be disabled\n", __func__); - spin_unlock(&dsi_irq_lock); - return; - } - - dsi_irq_enabled = 0; - spin_unlock(&dsi_irq_lock); -} - -/* * mipi dsi buf mechanism */ char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len) @@ -689,6 +645,30 @@ static int mdss_dsi_long_read_resp(struct dsi_buf *rp) return len; } +void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + int i; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201); + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */ + i = 0; + while (i++ < 50) { + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1); + /* Add sleep to get ~50 fps frame rate*/ + msleep(20); + } + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0); +} + void mdss_dsi_host_init(struct mipi_panel_info *pinfo, struct mdss_panel_data *pdata) { @@ -745,7 +725,7 @@ void mdss_dsi_host_init(struct mipi_panel_info *pinfo, if (pinfo->r_sel) data |= BIT(4); data |= (pinfo->dst_format & 0x0f); /* 4 bits */ - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x003c, data); + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0040, data); /* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */ data = pinfo->wr_mem_continue & 0x0ff; @@ -830,6 +810,7 @@ void mdss_dsi_host_init(struct mipi_panel_info *pinfo, dsi_ctrl |= BIT(0); /* enable dsi */ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl); + mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); /* enable dsi irq */ wmb(); } @@ -977,8 +958,6 @@ void mdss_dsi_op_mode_config(int mode, DSI_INTR_CMD_MDP_DONE_MASK; } - pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl); - if (ctrl_pdata->shared_pdata.broadcast_enable) if ((pdata->panel_info.pdest == DISPLAY_2) && (left_ctrl_pdata != NULL)) { @@ -994,17 +973,6 @@ void mdss_dsi_op_mode_config(int mode, wmb(); } -void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata) -{ - unsigned long flag; - - spin_lock_irqsave(&dsi_mdp_lock, flag); - mdss_dsi_enable_irq(pdata); - dsi_mdp_busy = true; - spin_unlock_irqrestore(&dsi_mdp_lock, flag); -} - - void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata) { u32 status; @@ -1116,7 +1084,7 @@ int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata, } spin_lock_irqsave(&dsi_mdp_lock, flag); - mdss_dsi_enable_irq(pdata); + mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); dsi_mdp_busy = true; spin_unlock_irqrestore(&dsi_mdp_lock, flag); @@ -1134,7 +1102,7 @@ int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata, spin_lock_irqsave(&dsi_mdp_lock, flag); dsi_mdp_busy = false; - mdss_dsi_disable_irq(pdata); + mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0); spin_unlock_irqrestore(&dsi_mdp_lock, flag); if (video_mode) @@ -1206,7 +1174,7 @@ int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata, } spin_lock_irqsave(&dsi_mdp_lock, flag); - mdss_dsi_enable_irq(pdata); + mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); dsi_mdp_busy = true; spin_unlock_irqrestore(&dsi_mdp_lock, flag); @@ -1243,7 +1211,7 @@ int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata, spin_lock_irqsave(&dsi_mdp_lock, flag); dsi_mdp_busy = false; - mdss_dsi_disable_irq(pdata); + mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0); spin_unlock_irqrestore(&dsi_mdp_lock, flag); if (pdata->panel_info.mipi.no_max_pkt_size) { @@ -1288,7 +1256,6 @@ int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp, struct mdss_panel_data *pdata) { int len; - int i; int domain = MDSS_IOMMU_DOMAIN_UNSECURE; char *bp; unsigned long size, addr; @@ -1303,12 +1270,6 @@ int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp, panel_data); bp = tp->data; - pr_debug("%s: ", __func__); - for (i = 0; i < tp->len; i++) - pr_debug("%x ", *bp++); - - pr_debug("\n"); - len = ALIGN(tp->len, 4); size = ALIGN(tp->len, SZ_4K); @@ -1495,6 +1456,8 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0); } + pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR); + if (isr & DSI_INTR_ERROR) mdss_dsi_error(dsi_base); @@ -1510,7 +1473,6 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) if (isr & DSI_INTR_CMD_MDP_DONE) { spin_lock(&dsi_mdp_lock); dsi_mdp_busy = false; - mdss_dsi_disable_irq_nosync(); spin_unlock(&dsi_mdp_lock); } diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index f173c4fdfb8b..85bd268d4753 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -13,11 +13,14 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/of.h> -#include <linux/qpnp/pin.h> +#include <linux/of_gpio.h> #include <linux/gpio.h> +#include <linux/qpnp/pin.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/leds.h> +#include <linux/pwm.h> +#include <linux/err.h> #include "mdss_dsi.h" @@ -30,6 +33,64 @@ DEFINE_LED_TRIGGER(bl_led_trigger); static struct mdss_dsi_phy_ctrl phy_params; +void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int ret; + + if (!gpio_is_valid(ctrl->pwm_gpio)) { + pr_err("%s: pwm_gpio=%d Invalid\n", __func__, + ctrl->pwm_gpio); + return; + } + + ret = gpio_request(ctrl->pwm_gpio, "disp_pwm"); + if (ret) { + pr_err("%s: pwm_gpio=%d request failed\n", __func__, + ctrl->pwm_gpio); + return; + } + + ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); + if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { + pr_err("%s: lpg_chan=%d pwm request failed", __func__, + ctrl->pwm_lpg_chan); + gpio_free(ctrl->pwm_gpio); + ctrl->pwm_gpio = -1; + } +} + +static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) +{ + int ret; + u32 duty; + + if (ctrl->pwm_bl == NULL) { + pr_err("%s: no PWM\n", __func__); + return; + } + + duty = level * ctrl->pwm_period; + duty /= ctrl->bklt_max; + + pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", + __func__, ctrl->bklt_ctrl, ctrl->pwm_period, + ctrl->pwm_gpio, ctrl->pwm_lpg_chan); + + pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__, + ctrl->ndx, level, duty); + + ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period); + if (ret) { + pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret); + return; + } + + ret = pwm_enable(ctrl->pwm_bl); + if (ret) + pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret); +} + + void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; @@ -84,46 +145,51 @@ static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); - if (ctrl_pdata->bl_ctrl) { - switch (ctrl_pdata->bl_ctrl) { - case BL_WLED: - led_trigger_event(bl_led_trigger, bl_level); - break; - - default: - pr_err("%s: Unknown bl_ctrl configuration\n", - __func__); - break; - } - } else - pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__); + switch (ctrl_pdata->bklt_ctrl) { + case BL_WLED: + led_trigger_event(bl_led_trigger, bl_level); + break; + case BL_PWM: + mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level); + break; + default: + pr_err("%s: Unknown bl_ctrl configuration\n", + __func__); + break; + } } +static char set_tear_on[2] = {0x35, 0x00}; +static struct dsi_cmd_desc dsi_tear_on_cmd = { + DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on}; + +static char set_tear_off[2] = {0x34, 0x00}; +static struct dsi_cmd_desc dsi_tear_off_cmd = { + DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off}; + static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) { struct mipi_panel_info *mipi; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mipi = &pdata->panel_info.mipi; - pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__, - mipi->mode); + pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); - if (mipi->mode == DSI_VIDEO_MODE) { + if (ctrl->on_cmds->size) mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, - ctrl_pdata->on_cmds->buf, - ctrl_pdata->on_cmds->size); - } else { - pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__); - return -EINVAL; - } + ctrl->on_cmds->buf, + ctrl->on_cmds->size); + + mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, + &dsi_tear_on_cmd, 1); return 0; } @@ -131,34 +197,33 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) { struct mipi_panel_info *mipi; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + + pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); + mipi = &pdata->panel_info.mipi; - pr_debug("%s:%d, debug info\n", __func__, __LINE__); + mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, + &dsi_tear_off_cmd, 1); - if (mipi->mode == DSI_VIDEO_MODE) { + if (ctrl->off_cmds->size) mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, - ctrl_pdata->off_cmds->buf, - ctrl_pdata->off_cmds->size); - } else { - pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__); - return -EINVAL; - } + ctrl->off_cmds->buf, + ctrl->off_cmds->size); return 0; } static int mdss_panel_parse_dt(struct platform_device *pdev, - struct mdss_panel_common_pdata *panel_data, - char *bl_ctrl) + struct mdss_panel_common_pdata *panel_data) { struct device_node *np = pdev->dev.of_node; u32 res[6], tmp; @@ -229,7 +294,32 @@ static int mdss_panel_parse_dt(struct platform_device *pdev, if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) { led_trigger_register_simple("bkl-trigger", &bl_led_trigger); pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__); - *bl_ctrl = BL_WLED; + + panel_data->panel_info.bklt_ctrl = BL_WLED; + } else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) { + panel_data->panel_info.bklt_ctrl = BL_PWM; + + rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp); + if (rc) { + pr_err("%s:%d, Error, dsi pwm_period\n", + __func__, __LINE__); + return -EINVAL; + } + panel_data->panel_info.pwm_period = tmp; + + rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp); + if (rc) { + pr_err("%s:%d, Error, dsi lpg channel\n", + __func__, __LINE__); + return -EINVAL; + } + panel_data->panel_info.pwm_lpg_chan = tmp; + + tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0); + panel_data->panel_info.pwm_gpio = tmp; + } else { + pr_debug("%s: Unknown backlight control\n", __func__); + panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL; } rc = of_property_read_u32_array(np, @@ -240,6 +330,13 @@ static int mdss_panel_parse_dt(struct platform_device *pdev, rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp); panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE); + rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp); + panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0); + + rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp); + panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0); + + rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-h-pulse-mode", &tmp); panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false); @@ -263,6 +360,26 @@ static int mdss_panel_parse_dt(struct platform_device *pdev, (!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE); rc = of_property_read_u32(np, + "qcom,mdss-pan-insert-dcs-cmd", &tmp); + panel_data->panel_info.mipi.insert_dcs_cmd = + (!rc ? tmp : 1); + + rc = of_property_read_u32(np, + "qcom,mdss-pan-wr-mem-continue", &tmp); + panel_data->panel_info.mipi.wr_mem_continue = + (!rc ? tmp : 0x3c); + + rc = of_property_read_u32(np, + "qcom,mdss-pan-wr-mem-start", &tmp); + panel_data->panel_info.mipi.wr_mem_start = + (!rc ? tmp : 0x2c); + + rc = of_property_read_u32(np, + "qcom,mdss-pan-te-sel", &tmp); + panel_data->panel_info.mipi.te_sel = + (!rc ? tmp : 1); + + rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dst-format", &tmp); panel_data->panel_info.mipi.dst_format = (!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888); @@ -313,6 +430,9 @@ static int mdss_panel_parse_dt(struct platform_device *pdev, rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp); panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60); + rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp); + panel_data->panel_info.clk_rate = (!rc ? tmp : 0); + data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len); if ((!data) || (len != 7)) { pr_err("%s:%d, Unable to read Phy regulator settings", @@ -533,7 +653,6 @@ static int mdss_dsi_panel_probe(struct platform_device *pdev) int rc = 0; static struct mdss_panel_common_pdata vendor_pdata; static const char *panel_name; - char bl_ctrl = UNKNOWN_CTRL; pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id); if (!pdev->dev.of_node) @@ -546,7 +665,7 @@ static int mdss_dsi_panel_probe(struct platform_device *pdev) else pr_info("%s: Panel Name = %s\n", __func__, panel_name); - rc = mdss_panel_parse_dt(pdev, &vendor_pdata, &bl_ctrl); + rc = mdss_panel_parse_dt(pdev, &vendor_pdata); if (rc) return rc; @@ -554,7 +673,7 @@ static int mdss_dsi_panel_probe(struct platform_device *pdev) vendor_pdata.off = mdss_dsi_panel_off; vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl; - rc = dsi_panel_device_register(pdev, &vendor_pdata, bl_ctrl); + rc = dsi_panel_device_register(pdev, &vendor_pdata); if (rc) return rc; diff --git a/drivers/video/fbdev/msm/mdss_edp.c b/drivers/video/fbdev/msm/mdss_edp.c index 842380a80078..efa88a347d29 100644 --- a/drivers/video/fbdev/msm/mdss_edp.c +++ b/drivers/video/fbdev/msm/mdss_edp.c @@ -363,7 +363,7 @@ static int mdss_edp_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_UNBLANK: rc = mdss_edp_on(pdata); break; - case MDSS_EVENT_TIMEGEN_OFF: + case MDSS_EVENT_PANEL_OFF: rc = mdss_edp_off(pdata); break; } diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index d416c4868e49..1c177dcf9df1 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2539,7 +2539,7 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, __func__, rc); break; - case MDSS_EVENT_TIMEGEN_ON: + case MDSS_EVENT_PANEL_ON: if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) { DEV_DBG("%s: Starting HDCP authentication\n", __func__); rc = hdmi_hdcp_authenticate( @@ -2575,7 +2575,7 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, } break; - case MDSS_EVENT_TIMEGEN_OFF: + case MDSS_EVENT_PANEL_OFF: hdmi_ctrl->timing_gen_on = false; break; diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 14c1e52f1969..67f175070445 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -319,6 +319,7 @@ int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en); int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata, u32 *offsets, u32 count); int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl); +int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl); int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl); int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index e8503219760a..7e0243b9e18b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -599,6 +599,15 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE; ctl->start_fnc = mdss_mdp_video_start; break; + case MIPI_CMD_PANEL: + if (pdata->panel_info.pdest == DISPLAY_1) + ctl->intf_num = MDSS_MDP_INTF1; + else + ctl->intf_num = MDSS_MDP_INTF2; + ctl->intf_type = MDSS_INTF_DSI; + ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE; + ctl->start_fnc = mdss_mdp_cmd_start; + break; case DTV_PANEL: ctl->intf_num = MDSS_MDP_INTF3; ctl->intf_type = MDSS_INTF_HDMI; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c new file mode 100644 index 000000000000..ebcc5ca33ee6 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -0,0 +1,335 @@ +/* Copyright (c) 2013, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include "mdss_panel.h" +#include "mdss_mdp.h" + +#define START_THRESHOLD 4 +#define CONTINUE_TRESHOLD 4 + +#define MAX_SESSIONS 2 + +struct mdss_mdp_cmd_ctx { + u32 pp_num; + u8 ref_cnt; + + struct completion pp_comp; + atomic_t vsync_ref; + spinlock_t vsync_lock; + mdp_vsync_handler_t vsync_handler; + int panel_on; + + /* te config */ + u8 tear_check; + u16 total_lcd_lines; + u16 v_porch; /* vertical porches */ + u32 vsync_cnt; +}; + +struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS]; + +static int mdss_mdp_cmd_tearcheck_cfg(u32 pp_num, + struct mdss_mdp_cmd_ctx *ctx, int enable) +{ + u32 off, cfg; + + off = MDSS_MDP_REG_PP_OFFSET(pp_num); + + cfg = BIT(19); /* VSYNC_COUNTER_EN */ + if (ctx->tear_check) + cfg |= BIT(20); /* VSYNC_IN_EN */ + cfg |= ctx->vsync_cnt; + + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT, + 0xfff0); /* set to verh height */ + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0); + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_RD_PTR_IRQ, 0); + + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_START_POS, ctx->v_porch); + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_SYNC_THRESH, + (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD)); + + MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable); + return 0; +} + +static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable) +{ + struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data; + struct mdss_panel_info *pinfo; + struct mdss_mdp_mixer *mixer; + + pinfo = &ctl->panel_data->panel_info; + + if (pinfo->mipi.vsync_enable && enable) { + u32 mdp_vsync_clk_speed_hz, total_lines; + u32 vsync_cnt_cfg_dem; + + mdss_mdp_vsync_clk_enable(1); + + mdp_vsync_clk_speed_hz = + mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC); + pr_debug("%s: vsync_clk_rate=%d\n", __func__, + mdp_vsync_clk_speed_hz); + + if (mdp_vsync_clk_speed_hz == 0) { + pr_err("can't get clk speed\n"); + return -EINVAL; + } + + ctx->tear_check = pinfo->mipi.hw_vsync_mode; + + total_lines = pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch + + pinfo->lcdc.v_pulse_width + pinfo->yres; + + vsync_cnt_cfg_dem = + mult_frac(pinfo->mipi.frame_rate * total_lines, + 1, 100); + + ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem; + + ctx->v_porch = pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch + + pinfo->lcdc.v_pulse_width; + ctx->total_lcd_lines = total_lines; + } else { + enable = 0; + } + + mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); + if (mixer) + mdss_mdp_cmd_tearcheck_cfg(mixer->num, ctx, enable); + + mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT); + if (mixer) + mdss_mdp_cmd_tearcheck_cfg(mixer->num, ctx, enable); + + return 0; +} + +static inline void cmd_readptr_irq_enable(struct mdss_mdp_ctl *ctl) +{ + struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data; + + if (atomic_inc_return(&ctx->vsync_ref) == 1) { + pr_debug("%s:\n", __func__); + mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num); + } +} + +static inline void cmd_readptr_irq_disable(struct mdss_mdp_ctl *ctl) +{ + struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data; + + if (atomic_dec_return(&ctx->vsync_ref) == 0) { + pr_debug("%s:\n", __func__); + mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, + ctx->pp_num); + } +} + +int mdss_mdp_cmd_set_vsync_handler(struct mdss_mdp_ctl *ctl, + mdp_vsync_handler_t vsync_handler) +{ + struct mdss_mdp_cmd_ctx *ctx; + unsigned long flags; + + ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data; + if (!ctx) { + pr_err("invalid ctx for ctl=%d\n", ctl->num); + return -ENODEV; + } + + spin_lock_irqsave(&ctx->vsync_lock, flags); + + if (!ctx->vsync_handler && vsync_handler) { + ctx->vsync_handler = vsync_handler; + cmd_readptr_irq_enable(ctl); + } else if (ctx->vsync_handler && !vsync_handler) { + cmd_readptr_irq_disable(ctl); + ctx->vsync_handler = vsync_handler; + } + + spin_unlock_irqrestore(&ctx->vsync_lock, flags); + + return 0; +} + +static void mdss_mdp_cmd_readptr_done(void *arg) +{ + struct mdss_mdp_ctl *ctl = arg; + struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data; + ktime_t vsync_time; + + if (!ctx) { + pr_err("invalid ctx\n"); + return; + } + + pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num); + + vsync_time = ktime_get(); + + spin_lock(&ctx->vsync_lock); + if (ctx->vsync_handler) + ctx->vsync_handler(ctl, vsync_time); + spin_unlock(&ctx->vsync_lock); +} + +static void mdss_mdp_cmd_pingpong_done(void *arg) +{ + struct mdss_mdp_ctl *ctl = arg; + struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data; + + pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx); + + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num); + + if (ctx) + complete(&ctx->pp_comp); +} + +int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) +{ + struct mdss_mdp_cmd_ctx *ctx; + int rc; + + ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data; + pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__, + ctl->intf_num, ctx); + + if (!ctx) { + pr_err("invalid ctx\n"); + return -ENODEV; + } + + if (ctx->panel_on == 0) { + rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL); + WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc); + + ctx->panel_on++; + + rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL); + WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc); + } + + INIT_COMPLETION(ctx->pp_comp); + mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num); + + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1); + + wait_for_completion_interruptible(&ctx->pp_comp); + + return 0; +} + +int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) +{ + struct mdss_mdp_cmd_ctx *ctx; + int ret; + + pr_debug("%s: +\n", __func__); + + ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data; + if (!ctx) { + pr_err("invalid ctx\n"); + return -ENODEV; + } + + ctx->panel_on = 0; + + mdss_mdp_cmd_set_vsync_handler(ctl, NULL); + + mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num, + NULL, NULL); + 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; + + ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL); + WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret); + + ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL); + WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + + pr_debug("%s:-\n", __func__); + + return 0; +} + +int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl) +{ + struct mdss_mdp_cmd_ctx *ctx; + struct mdss_mdp_mixer *mixer; + int i, ret; + + pr_debug("%s:+\n", __func__); + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); + + mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); + if (!mixer) { + pr_err("mixer not setup correctly\n"); + return -ENODEV; + } + + for (i = 0; i < MAX_SESSIONS; i++) { + ctx = &mdss_mdp_cmd_ctx_list[i]; + if (ctx->ref_cnt == 0) { + ctx->ref_cnt++; + break; + } + } + if (i == MAX_SESSIONS) { + pr_err("too many sessions\n"); + return -ENOMEM; + } + + ctl->priv_data = ctx; + if (!ctx) { + pr_err("invalid ctx\n"); + return -ENODEV; + } + + ctx->pp_num = mixer->num; + init_completion(&ctx->pp_comp); + spin_lock_init(&ctx->vsync_lock); + atomic_set(&ctx->vsync_ref, 0); + + mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num, + mdss_mdp_cmd_readptr_done, ctl); + + mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num, + mdss_mdp_cmd_pingpong_done, ctl); + + ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1); + if (ret) { + pr_err("tearcheck setup failed\n"); + return ret; + } + + ctl->stop_fnc = mdss_mdp_cmd_stop; + ctl->display_fnc = mdss_mdp_cmd_kickoff; + ctl->set_vsync_handler = mdss_mdp_cmd_set_vsync_handler; + + pr_debug("%s:-\n", __func__); + + return 0; +} + diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index dab8674cfd35..e7f70b6c9d5c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -242,7 +242,7 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl) mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); ctx->timegen_en = false; - rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_OFF, NULL); + rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL); WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc); mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN, @@ -359,8 +359,8 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg) rc, ctl->num); ctx->timegen_en = true; - rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL); - WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc); + rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL); + WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc); } return 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index 0967d3d80271..143727525572 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -43,6 +43,9 @@ enum { MDP_INTR_PING_PONG_0, MDP_INTR_PING_PONG_1, MDP_INTR_PING_PONG_2, + MDP_INTR_PING_PONG_0_RD_PTR, + MDP_INTR_PING_PONG_1_RD_PTR, + MDP_INTR_PING_PONG_2_RD_PTR, MDP_INTR_WB_0, MDP_INTR_WB_1, MDP_INTR_WB_2, @@ -70,6 +73,9 @@ static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num) case MDSS_MDP_IRQ_PING_PONG_COMP: index = MDP_INTR_PING_PONG_0 + intf_num; break; + case MDSS_MDP_IRQ_PING_PONG_RD_PTR: + index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num; + break; case MDSS_MDP_IRQ_WB_ROT_COMP: index = MDP_INTR_WB_0 + intf_num; break; @@ -127,11 +133,12 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr == 0) goto mdp_isr_done; - pr_debug("isr=%x\n", isr); mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN); MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr); + pr_debug("%s: isr=%x mask=%x\n", __func__, isr, mask); + isr &= mask; if (isr == 0) goto mdp_isr_done; @@ -157,6 +164,15 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE) mdss_mdp_intr_done(MDP_INTR_PING_PONG_2); + if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR) + mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR); + + if (isr & MDSS_MDP_INTR_PING_PONG_1_RD_PTR) + mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_RD_PTR); + + if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR) + mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR); + if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 31fb2e7991e8..23f7445804bf 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -58,9 +58,9 @@ enum { enum mdss_intf_events { MDSS_EVENT_RESET, MDSS_EVENT_UNBLANK, - MDSS_EVENT_TIMEGEN_ON, + MDSS_EVENT_PANEL_ON, MDSS_EVENT_BLANK, - MDSS_EVENT_TIMEGEN_OFF, + MDSS_EVENT_PANEL_OFF, MDSS_EVENT_CLOSE, MDSS_EVENT_SUSPEND, MDSS_EVENT_RESUME, @@ -69,19 +69,7 @@ enum mdss_intf_events { MDSS_EVENT_FB_REGISTERED, }; -/* panel info type */ struct lcd_panel_info { - u32 vsync_enable; - u32 refx100; - u32 v_back_porch; - u32 v_front_porch; - u32 v_pulse_width; - u32 hw_vsync_mode; - u32 vsync_notifier_period; - u32 rev; -}; - -struct lcdc_panel_info { u32 h_back_porch; u32 h_front_porch; u32 h_pulse_width; @@ -153,6 +141,9 @@ struct mipi_panel_info { char no_max_pkt_size; /* Clock required during LP commands */ char force_clk_lane_hs; + + char vsync_enable; + char hw_vsync_mode; }; enum lvds_mode { @@ -183,13 +174,16 @@ struct mdss_panel_info { u32 is_3d_panel; u32 out_format; u32 vic; /* video identification code */ + int bklt_ctrl; /* backlight ctrl */ + int pwm_gpio; + int pwm_lpg_chan; + int pwm_period; u32 cont_splash_enabled; struct ion_handle *splash_ihdl; u32 panel_power_on; - struct lcd_panel_info lcd; - struct lcdc_panel_info lcdc; + struct lcd_panel_info lcdc; struct mipi_panel_info mipi; struct lvds_panel_info lvds; }; |
