summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorChandan Uddaraju <chandanu@codeaurora.org>2013-03-26 14:10:40 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:15:42 -0700
commite1095524a09054d022e15c5e63574d1ef3f5cc66 (patch)
tree4d040c6e97fc95d57134a43745d2ad9907d82e8b /drivers/video/fbdev
parent4e3d5715cff9c832fc3066a7a8196f9078845f45 (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/Makefile1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c198
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h17
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c154
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c201
-rw-r--r--drivers/video/fbdev/msm/mdss_edp.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c335
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c18
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h26
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;
};