summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2014-03-24 10:39:01 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-06-03 23:02:07 -0500
commit712701a17813a3c149d4a52a7bfa78368c79addf (patch)
tree6881bcae23859bd016c9e121aa81472b1fee1c51 /drivers
parent3ef07276ad0d6a16cf42639eda6cad320f4cd017 (diff)
ENGR00304402 video: mxc LDB: Enable LDB channel after display controller
In order to avoid any random pixelation issue, we should follow a correct display controller/LDB initialization sequence, that is, LDB channel should be enabled after its relevant display controller is enabled. Since the enable() callback of the mxc display driver is called after a display controller is enabled, this patch uses the enable()/disable() callbacks to replace the fb notifier callback implemented in the LDB driver. Also, we disable a LDB channel in the setup() callback of the mxc display driver to make sure of the correct sequence in any fb set_par() function. As the enable()/disable() callbacks are always invoked with fb_blank(), this patch drops the suspend()/resume() functions of the LDB driver which do nothing but enable/disable LDB channels. We also remove the code to enable ldb di clocks because they can be enabled when their relevant child pixel clocks are enabled. Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/mxc/ldb.c139
-rw-r--r--drivers/video/mxc/mipi_dsi.c15
-rw-r--r--drivers/video/mxc/mxc_dispdrv.h6
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c6
-rw-r--r--drivers/video/mxc_hdmi.c8
5 files changed, 54 insertions, 120 deletions
diff --git a/drivers/video/mxc/ldb.c b/drivers/video/mxc/ldb.c
index 19de5c541fdd..12dd03684e0d 100644
--- a/drivers/video/mxc/ldb.c
+++ b/drivers/video/mxc/ldb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -84,7 +84,6 @@ struct ldb_data {
uint32_t *reg;
uint32_t *control_reg;
uint32_t *gpr3_reg;
- uint32_t control_reg_data;
struct regulator *lvds_bg_reg;
int mode;
bool inited;
@@ -92,13 +91,11 @@ struct ldb_data {
struct clk *di_clk;
struct clk *ldb_di_clk;
bool active;
- bool clk_en;
int ipu;
int di;
uint32_t ch_mask;
uint32_t ch_val;
} setting[2];
- struct notifier_block nb;
};
static int g_ldb_mode;
@@ -222,7 +219,7 @@ static int find_ldb_setting(struct ldb_data *ldb, struct fb_info *fbi)
static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
{
- uint32_t reg, val;
+ uint32_t reg;
uint32_t pixel_clk, rounded_pixel_clk;
struct clk *ldb_clk_parent;
struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
@@ -234,15 +231,10 @@ static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
di = ldb->setting[setting_idx].di;
- /* restore channel mode setting */
- val = readl(ldb->control_reg);
- val |= ldb->setting[setting_idx].ch_val;
- writel(val, ldb->control_reg);
- dev_dbg(&ldb->pdev->dev, "LDB setup, control reg:0x%x\n",
- readl(ldb->control_reg));
-
- /* vsync setup */
reg = readl(ldb->control_reg);
+ /* clear channel mode */
+ reg &= ~ldb->setting[setting_idx].ch_mask;
+ /* vsync setup */
if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {
if (di == 0)
reg = (reg & ~LDB_DI0_VS_POL_MASK)
@@ -261,8 +253,6 @@ static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
writel(reg, ldb->control_reg);
/* clk setup */
- if (ldb->setting[setting_idx].clk_en)
- clk_disable(ldb->setting[setting_idx].ldb_di_clk);
pixel_clk = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;
ldb_clk_parent = clk_get_parent(ldb->setting[setting_idx].ldb_di_clk);
if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1))
@@ -272,76 +262,44 @@ static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
rounded_pixel_clk = clk_round_rate(ldb->setting[setting_idx].ldb_di_clk,
pixel_clk);
clk_set_rate(ldb->setting[setting_idx].ldb_di_clk, rounded_pixel_clk);
- clk_enable(ldb->setting[setting_idx].ldb_di_clk);
- if (!ldb->setting[setting_idx].clk_en)
- ldb->setting[setting_idx].clk_en = true;
return 0;
}
-int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
+static int ldb_disp_enable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
{
- struct ldb_data *ldb = container_of(nb, struct ldb_data, nb);
- struct fb_event *event = v;
- struct fb_info *fbi = event->info;
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
int index;
- uint32_t data;
+ uint32_t reg;
index = find_ldb_setting(ldb, fbi);
if (index < 0)
- return 0;
+ return index;
- fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
- &fbi->modelist);
-
- if (!fbi->mode) {
- dev_warn(&ldb->pdev->dev,
- "LDB: can not find mode for xres=%d, yres=%d\n",
- fbi->var.xres, fbi->var.yres);
- if (ldb->setting[index].clk_en) {
- clk_disable(ldb->setting[index].ldb_di_clk);
- ldb->setting[index].clk_en = false;
- data = readl(ldb->control_reg);
- data &= ~ldb->setting[index].ch_mask;
- writel(data, ldb->control_reg);
- }
- return 0;
- }
+ reg = readl(ldb->control_reg);
+ reg |= ldb->setting[index].ch_val;
+ writel(reg, ldb->control_reg);
- switch (val) {
- case FB_EVENT_BLANK:
- {
- if (*((int *)event->data) == FB_BLANK_UNBLANK) {
- if (!ldb->setting[index].clk_en) {
- clk_enable(ldb->setting[index].ldb_di_clk);
- ldb->setting[index].clk_en = true;
- }
- } else {
- if (ldb->setting[index].clk_en) {
- clk_disable(ldb->setting[index].ldb_di_clk);
- ldb->setting[index].clk_en = false;
- data = readl(ldb->control_reg);
- data &= ~ldb->setting[index].ch_mask;
- writel(data, ldb->control_reg);
- dev_dbg(&ldb->pdev->dev,
- "LDB blank, control reg:0x%x\n",
- readl(ldb->control_reg));
- }
- }
- break;
- }
- case FB_EVENT_SUSPEND:
- if (ldb->setting[index].clk_en) {
- clk_disable(ldb->setting[index].ldb_di_clk);
- ldb->setting[index].clk_en = false;
- }
- break;
- default:
- break;
- }
return 0;
}
+static void ldb_disp_disable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ int index;
+ uint32_t reg;
+
+ index = find_ldb_setting(ldb, fbi);
+ if (index < 0)
+ return;
+
+ reg = readl(ldb->control_reg);
+ reg &= ~ldb->setting[index].ch_mask;
+ writel(reg, ldb->control_reg);
+}
+
#define LVDS_MUX_CTL_WIDTH 2
#define LVDS_MUX_CTL_MASK 3
#define LVDS0_MUX_CTL_OFFS 6
@@ -610,14 +568,6 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk);
- /* fb notifier for clk setting */
- ldb->nb.notifier_call = ldb_fb_event,
- ret = fb_register_client(&ldb->nb);
- if (ret < 0) {
- iounmap(ldb->reg);
- return ret;
- }
-
ldb->inited = true;
} else { /* second time for separate mode */
char di_clk[] = "ipu1_di0_clk";
@@ -754,8 +704,6 @@ static void ldb_disp_deinit(struct mxc_dispdrv_handle *disp)
clk_put(ldb->setting[i].ldb_di_clk);
}
- fb_unregister_client(&ldb->nb);
-
iounmap(ldb->reg);
}
@@ -764,33 +712,10 @@ static struct mxc_dispdrv_driver ldb_drv = {
.init = ldb_disp_init,
.deinit = ldb_disp_deinit,
.setup = ldb_disp_setup,
+ .enable = ldb_disp_enable,
+ .disable = ldb_disp_disable,
};
-static int ldb_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
- uint32_t data;
-
- if (!ldb->inited)
- return 0;
- data = readl(ldb->control_reg);
- ldb->control_reg_data = data;
- data &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
- writel(data, ldb->control_reg);
-
- return 0;
-}
-
-static int ldb_resume(struct platform_device *pdev)
-{
- struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
-
- if (!ldb->inited)
- return 0;
- writel(ldb->control_reg_data, ldb->control_reg);
-
- return 0;
-}
/*!
* This function is called by the driver framework to initialize the LDB
* device.
@@ -839,8 +764,6 @@ static struct platform_driver mxcldb_driver = {
},
.probe = ldb_probe,
.remove = ldb_remove,
- .suspend = ldb_suspend,
- .resume = ldb_resume,
};
static int __init ldb_init(void)
diff --git a/drivers/video/mxc/mipi_dsi.c b/drivers/video/mxc/mipi_dsi.c
index 8434e14f9746..36e5a2e96936 100644
--- a/drivers/video/mxc/mipi_dsi.c
+++ b/drivers/video/mxc/mipi_dsi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. 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 as published by
@@ -621,7 +621,8 @@ static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
return 0;
}
-int mipi_dsi_enable(struct mxc_dispdrv_handle *disp)
+static int mipi_dsi_enable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
{
int err;
struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
@@ -649,6 +650,14 @@ int mipi_dsi_enable(struct mxc_dispdrv_handle *disp)
return 0;
}
+static void mipi_dsi_disable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+}
+
static int mipi_dsi_disp_init(struct mxc_dispdrv_handle *disp,
struct mxc_dispdrv_setting *setting)
{
@@ -906,7 +915,7 @@ static struct mxc_dispdrv_driver mipi_dsi_drv = {
.init = mipi_dsi_disp_init,
.deinit = mipi_dsi_disp_deinit,
.enable = mipi_dsi_enable,
- .disable = mipi_dsi_power_off,
+ .disable = mipi_dsi_disable,
};
/**
diff --git a/drivers/video/mxc/mxc_dispdrv.h b/drivers/video/mxc/mxc_dispdrv.h
index c6d05fa37799..c9923900bbe8 100644
--- a/drivers/video/mxc/mxc_dispdrv.h
+++ b/drivers/video/mxc/mxc_dispdrv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -35,9 +35,9 @@ struct mxc_dispdrv_driver {
int (*init) (struct mxc_dispdrv_handle *, struct mxc_dispdrv_setting *);
void (*deinit) (struct mxc_dispdrv_handle *);
/* display driver enable function for extension */
- int (*enable) (struct mxc_dispdrv_handle *);
+ int (*enable) (struct mxc_dispdrv_handle *, struct fb_info *);
/* display driver disable function, called at early part of fb_blank */
- void (*disable) (struct mxc_dispdrv_handle *);
+ void (*disable) (struct mxc_dispdrv_handle *, struct fb_info *);
/* display driver setup function, called at early part of fb_set_par */
int (*setup) (struct mxc_dispdrv_handle *, struct fb_info *fbi);
};
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index 4c98d51f13b0..bfa588f62d85 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -647,7 +647,7 @@ static int mxcfb_set_par(struct fb_info *fbi)
ipu_enable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->enable) {
- retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv);
+ retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv, fbi);
if (retval < 0) {
dev_err(fbi->device, "enable error, dispdrv:%s.\n",
mxc_fbi->dispdrv->drv->name);
@@ -1362,7 +1362,7 @@ static int mxcfb_blank(int blank, struct fb_info *info)
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->disable)
- mxc_fbi->dispdrv->drv->disable(mxc_fbi->dispdrv);
+ mxc_fbi->dispdrv->drv->disable(mxc_fbi->dispdrv, info);
ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
if (mxc_fbi->ipu_di >= 0)
ipu_uninit_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di);
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c
index c5069aa19eb0..c60c7f381438 100644
--- a/drivers/video/mxc_hdmi.c
+++ b/drivers/video/mxc_hdmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1964,14 +1964,16 @@ static void mxc_hdmi_cable_connected(struct mxc_hdmi *hdmi)
dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
}
-static int mxc_hdmi_power_on(struct mxc_dispdrv_handle *disp)
+static int mxc_hdmi_power_on(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
{
struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
mxc_hdmi_phy_init(hdmi);
return 0;
}
-static void mxc_hdmi_power_off(struct mxc_dispdrv_handle *disp)
+static void mxc_hdmi_power_off(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
{
struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
mxc_hdmi_phy_disable(hdmi);