aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Chen <b02280@freescale.com>2011-11-23 14:43:57 +0800
committerEric Miao <eric.miao@linaro.org>2011-12-02 14:41:50 +0800
commitf7ddd9adf451d73f0d653a86b629b6e4f08eeb07 (patch)
treebf6aea923bfc7874ecc8092fe98bf6be955de7f4
parent5a5a3b462dfad82dfb4a9b86d3fe37e12842893e (diff)
IPU3 FB: porting to fsl imx_2.6.38 branch base
to base commit 433c6306fe9455163cff3591b4cf8e2f22bc6cc8 add ipuv3 fb driver. add mxc display driver. add mxc edid driver. add display device driver for lcd/ldb/tve/dvi/sii902x Signed-off-by: Jason Chen <jason.chen@linaro.org>
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_edid.h (renamed from drivers/video/mxc/mxc_edid.h)4
-rw-r--r--drivers/video/mxc/Kconfig7
-rw-r--r--drivers/video/mxc/Makefile4
-rw-r--r--drivers/video/mxc/ldb.c139
-rw-r--r--drivers/video/mxc/mxc_dispdrv.c1
-rw-r--r--drivers/video/mxc/mxc_dvi.c380
-rw-r--r--drivers/video/mxc/mxc_edid.c128
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c82
-rw-r--r--drivers/video/mxc/mxc_lcdif.c144
-rw-r--r--drivers/video/mxc/mxcfb_sii902x.c8
-rw-r--r--drivers/video/mxc/tve.c1
-rw-r--r--include/linux/fsl_devices.h8
12 files changed, 821 insertions, 85 deletions
diff --git a/drivers/video/mxc/mxc_edid.h b/arch/arm/plat-mxc/include/mach/mxc_edid.h
index ec65a5fa9bd..59688f657a2 100644
--- a/drivers/video/mxc/mxc_edid.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_edid.h
@@ -26,6 +26,9 @@
#ifndef MXC_EDID_H
#define MXC_EDID_H
+#define FB_VMODE_ASPECT_4_3 0x10
+#define FB_VMODE_ASPECT_16_9 0x20
+
struct mxc_edid_cfg {
bool cea_underscan;
bool cea_basicaudio;
@@ -42,6 +45,7 @@ struct mxc_edid_cfg {
};
int mxc_edid_var_to_vic(struct fb_var_screeninfo *var);
+int mxc_edid_mode_to_vic(const struct fb_videomode *mode);
int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr,
unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi);
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig
index bb836c3a63f..053f62b7632 100644
--- a/drivers/video/mxc/Kconfig
+++ b/drivers/video/mxc/Kconfig
@@ -14,6 +14,11 @@ config FB_MXC
If you plan to use the LCD display with your MXC system, say
Y here.
+config FB_MXC_EDID
+ depends on FB_MXC && I2C
+ tristate "MXC EDID support"
+ default y
+
config FB_MXC_SYNC_PANEL
depends on FB_MXC
tristate "Synchronous Panel Framebuffer"
@@ -25,7 +30,7 @@ config FB_MXC_TVOUT_TVE
depends on MXC_IPU_V3
config FB_MXC_SII902X
- depends on FB_MXC_SYNC_PANEL
+ depends on FB_MXC_SYNC_PANEL && I2C
tristate "Si Image SII9022 DVI/HDMI Interface Chip"
config FB_MXC_LDB
diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile
index a5cf5a3eedb..e0d47ed90b4 100644
--- a/drivers/video/mxc/Makefile
+++ b/drivers/video/mxc/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o
obj-$(CONFIG_FB_MXC_SII902X) += mxcfb_sii902x.o
obj-$(CONFIG_FB_MXC_LDB) += ldb.o
-obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
-obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_ipuv3_fb.o
+obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o mxc_dvi.o
+obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
diff --git a/drivers/video/mxc/ldb.c b/drivers/video/mxc/ldb.c
index 401ebb4c3a5..18a204f2191 100644
--- a/drivers/video/mxc/ldb.c
+++ b/drivers/video/mxc/ldb.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/ipu.h>
#include <linux/mxcfb.h>
+#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include <linux/fsl_devices.h>
@@ -296,6 +297,116 @@ int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
return 0;
}
+#define LVDS0_MUX_CTL_MASK (3 << 6)
+#define LVDS1_MUX_CTL_MASK (3 << 8)
+#define LVDS0_MUX_CTL_OFFS 6
+#define LVDS1_MUX_CTL_OFFS 8
+#define ROUTE_IPU0_DI0 0
+#define ROUTE_IPU0_DI1 1
+#define ROUTE_IPU1_DI0 2
+#define ROUTE_IPU1_DI1 3
+static int ldb_ipu_ldb_route(int ipu, int di, struct ldb_data *ldb)
+{
+ uint32_t reg;
+ int mode = ldb->mode;
+
+ reg = readl(ldb->gpr3_reg);
+ if ((mode == LDB_SPL_DI0) || (mode == LDB_DUL_DI0)) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ if (ipu == 0)
+ reg |= (ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU0_DI0 << LVDS1_MUX_CTL_OFFS);
+ else
+ reg |= (ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU1_DI0 << LVDS1_MUX_CTL_OFFS);
+ dev_dbg(&ldb->pdev->dev,
+ "Dual/Split mode both channels route to IPU%d-DI0\n", ipu);
+ } else if ((mode == LDB_SPL_DI1) || (mode == LDB_DUL_DI1)) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ if (ipu == 0)
+ reg |= (ROUTE_IPU0_DI1 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS);
+ else
+ reg |= (ROUTE_IPU1_DI1 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS);
+ dev_dbg(&ldb->pdev->dev,
+ "Dual/Split mode both channels route to IPU%d-DI1\n", ipu);
+ } else if (mode == LDB_SIN0) {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ if ((ipu == 0) && (di == 0))
+ reg |= ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS;
+ else if ((ipu == 0) && (di == 1))
+ reg |= ROUTE_IPU0_DI1 << LVDS0_MUX_CTL_OFFS;
+ else if ((ipu == 1) && (di == 0))
+ reg |= ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI1 << LVDS0_MUX_CTL_OFFS;
+ dev_dbg(&ldb->pdev->dev,
+ "Single mode channel 0 route to IPU%d-DI%d\n", ipu, di);
+ } else if (mode == LDB_SIN1) {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ if ((ipu == 0) && (di == 0))
+ reg |= ROUTE_IPU0_DI0 << LVDS1_MUX_CTL_OFFS;
+ else if ((ipu == 0) && (di == 1))
+ reg |= ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS;
+ else if ((ipu == 1) && (di == 0))
+ reg |= ROUTE_IPU1_DI0 << LVDS1_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS;
+ dev_dbg(&ldb->pdev->dev,
+ "Single mode channel 1 route to IPU%d-DI%d\n", ipu, di);
+ } else {
+ static bool first = true;
+ int channel;
+
+ if (first) {
+ if (mode == LDB_SEP0) {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ channel = 0;
+ } else {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ channel = 1;
+ }
+ first = false;
+ } else {
+ if (mode == LDB_SEP0) {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ channel = 1;
+ } else {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ channel = 0;
+ }
+ }
+
+ if ((ipu == 0) && (di == 0)) {
+ if (channel == 0)
+ reg |= ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU0_DI0 << LVDS1_MUX_CTL_OFFS;
+ } else if ((ipu == 0) && (di == 1)) {
+ if (channel == 0)
+ reg |= ROUTE_IPU0_DI1 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS;
+ } else if ((ipu == 1) && (di == 0)) {
+ if (channel == 0)
+ reg |= ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI0 << LVDS1_MUX_CTL_OFFS;
+ } else {
+ if (channel == 0)
+ reg |= ROUTE_IPU1_DI1 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS;
+ }
+
+ dev_dbg(&ldb->pdev->dev, "Separate mode channel %d route to IPU%d-DI%d\n", channel, ipu, di);
+ }
+ writel(reg, ldb->gpr3_reg);
+
+ return 0;
+}
+
static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
{
int ret = 0, i;
@@ -429,7 +540,11 @@ static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
writel(reg, ldb->control_reg);
/* clock setting */
- ldb_clk[6] += setting->disp_id;
+ if (cpu_is_mx6q() &&
+ ((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1)))
+ ldb_clk[6] += lvds_channel;
+ else
+ ldb_clk[6] += setting->disp_id;
ldb->ldb_di_clk[0] = clk_get(&ldb->pdev->dev, ldb_clk);
if (IS_ERR(ldb->ldb_di_clk[0])) {
dev_err(&ldb->pdev->dev, "get ldb clk0 failed\n");
@@ -473,8 +588,13 @@ static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
return -EINVAL;
}
- setting->dev_id = plat_data->ipu_id;
- setting->disp_id = !plat_data->disp_id;
+ if (cpu_is_mx6q()) {
+ setting->dev_id = plat_data->sec_ipu_id;
+ setting->disp_id = plat_data->sec_disp_id;
+ } else {
+ setting->dev_id = plat_data->ipu_id;
+ setting->disp_id = !plat_data->disp_id;
+ }
/* second output is LVDS0 or LVDS1 */
if (ldb->mode == LDB_SEP0)
@@ -506,7 +626,10 @@ static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
writel(reg, ldb->control_reg);
/* clock setting */
- ldb_clk[6] += setting->disp_id;
+ if (cpu_is_mx6q())
+ ldb_clk[6] += lvds_channel;
+ else
+ ldb_clk[6] += setting->disp_id;
ldb->ldb_di_clk[1] = clk_get(&ldb->pdev->dev, ldb_clk);
if (IS_ERR(ldb->ldb_di_clk[1])) {
dev_err(&ldb->pdev->dev, "get ldb clk1 failed\n");
@@ -525,6 +648,14 @@ static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
setting_idx = 1;
}
+ if (cpu_is_mx6q()) {
+ reg = readl(ldb->control_reg);
+ reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
+ reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI1;
+ writel(reg, ldb->control_reg);
+ ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);
+ }
+
/*
* ldb_di0_clk -> ipux_di0_clk
* ldb_di1_clk -> ipux_di1_clk
diff --git a/drivers/video/mxc/mxc_dispdrv.c b/drivers/video/mxc/mxc_dispdrv.c
index 06b7af944f5..797d96b98b7 100644
--- a/drivers/video/mxc/mxc_dispdrv.c
+++ b/drivers/video/mxc/mxc_dispdrv.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <linux/export.h>
#include "mxc_dispdrv.h"
static LIST_HEAD(dispdrv_list);
diff --git a/drivers/video/mxc/mxc_dvi.c b/drivers/video/mxc/mxc_dvi.c
new file mode 100644
index 00000000000..6939cd0c639
--- /dev/null
+++ b/drivers/video/mxc/mxc_dvi.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2011 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * 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.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*!
+ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+/*!
+ * @file mxc_dvi.c
+ *
+ * @brief MXC DVI driver
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ipu.h>
+#include <linux/mxcfb.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <mach/mxc_edid.h>
+#include "mxc_dispdrv.h"
+#include "../edid.h"
+
+#define MXC_EDID_LENGTH (EDID_LENGTH*4)
+
+#define DISPDRV_DVI "dvi"
+
+struct mxc_dvi_data {
+ struct i2c_client *client;
+ struct platform_device *pdev;
+ struct mxc_dispdrv_entry *disp_dvi;
+ struct delayed_work det_work;
+ struct fb_info *fbi;
+ struct mxc_edid_cfg edid_cfg;
+ u8 cable_plugin;
+ u8 edid[MXC_EDID_LENGTH];
+
+ u32 ipu;
+ u32 di;
+ void (*init)(void);
+ int (*update)(void);
+ struct regulator *analog_reg;
+};
+
+static ssize_t mxc_dvi_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_dvi_data *dvi = dev_get_drvdata(dev);
+
+ if (dvi->cable_plugin == 0)
+ strcpy(buf, "plugout\n");
+ else
+ strcpy(buf, "plugin\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(cable_state, S_IRUGO, mxc_dvi_show_state, NULL);
+
+static ssize_t mxc_dvi_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_dvi_data *dvi = dev_get_drvdata(dev);
+
+ strcpy(buf, dvi->fbi->fix.id);
+ sprintf(buf+strlen(buf), "\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(fb_name, S_IRUGO, mxc_dvi_show_name, NULL);
+
+static ssize_t mxc_dvi_show_edid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_dvi_data *dvi = dev_get_drvdata(dev);
+ int i, j, len = 0;
+
+ for (j = 0; j < MXC_EDID_LENGTH/16; j++) {
+ for (i = 0; i < 16; i++)
+ len += sprintf(buf+len, "0x%02X ",
+ dvi->edid[j*16 + i]);
+ len += sprintf(buf+len, "\n");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(edid, S_IRUGO, mxc_dvi_show_edid, NULL);
+
+static void det_worker(struct work_struct *work)
+{
+ struct delayed_work *delay_work = to_delayed_work(work);
+ struct mxc_dvi_data *dvi =
+ container_of(delay_work, struct mxc_dvi_data, det_work);
+ char event_string[16];
+ char *envp[] = { event_string, NULL };
+
+ /* cable connection changes */
+ if (dvi->update()) {
+ u8 edid_old[MXC_EDID_LENGTH];
+ dvi->cable_plugin = 1;
+ sprintf(event_string, "EVENT=plugin");
+
+ memcpy(edid_old, dvi->edid, MXC_EDID_LENGTH);
+
+ if (mxc_edid_read(dvi->client->adapter, dvi->client->addr,
+ dvi->edid, &dvi->edid_cfg, dvi->fbi) < 0)
+ dev_err(&dvi->client->dev,
+ "MXC dvi: read edid fail\n");
+ else {
+ if (!memcmp(edid_old, dvi->edid, MXC_EDID_LENGTH))
+ dev_info(&dvi->client->dev,
+ "Sii902x: same edid\n");
+ else if (dvi->fbi->monspecs.modedb_len > 0) {
+ int i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+
+ fb_destroy_modelist(&dvi->fbi->modelist);
+
+ for (i = 0; i < dvi->fbi->monspecs.modedb_len; i++)
+ /*FIXME now we do not support interlaced mode */
+ if (!(dvi->fbi->monspecs.modedb[i].vmode & FB_VMODE_INTERLACED))
+ fb_add_videomode(&dvi->fbi->monspecs.modedb[i],
+ &dvi->fbi->modelist);
+
+ fb_var_to_videomode(&m, &dvi->fbi->var);
+ mode = fb_find_nearest_mode(&m,
+ &dvi->fbi->modelist);
+
+ fb_videomode_to_var(&dvi->fbi->var, mode);
+
+ dvi->fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ dvi->fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(dvi->fbi, &dvi->fbi->var);
+ dvi->fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ }
+ }
+ } else {
+ dvi->cable_plugin = 0;
+ sprintf(event_string, "EVENT=plugout");
+ }
+
+ kobject_uevent_env(&dvi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+}
+
+static irqreturn_t mxc_dvi_detect_handler(int irq, void *data)
+{
+ struct mxc_dvi_data *dvi = data;
+ schedule_delayed_work(&(dvi->det_work), msecs_to_jiffies(300));
+ return IRQ_HANDLED;
+}
+
+static int dvi_init(struct mxc_dispdrv_entry *disp)
+{
+ int ret = 0;
+ struct mxc_dvi_data *dvi = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_dvi_platform_data *plat = dvi->client->dev.platform_data;
+
+ setting->dev_id = dvi->ipu = plat->ipu_id;
+ setting->disp_id = dvi->di = plat->disp_id;
+ setting->if_fmt = IPU_PIX_FMT_RGB24;
+ dvi->fbi = setting->fbi;
+ dvi->init = plat->init;
+ dvi->update = plat->update;
+
+ dvi->analog_reg = regulator_get(&dvi->pdev->dev, plat->analog_regulator);
+ if (!IS_ERR(dvi->analog_reg)) {
+ regulator_set_voltage(dvi->analog_reg, 2775000, 2775000);
+ regulator_enable(dvi->analog_reg);
+ }
+
+ if (dvi->init)
+ dvi->init();
+
+ /* get video mode from edid */
+ if (!dvi->update)
+ return -EINVAL;
+ else {
+ bool found = false;
+
+ INIT_LIST_HEAD(&dvi->fbi->modelist);
+ if (dvi->update()) {
+ dvi->cable_plugin = 1;
+ /* try to read edid */
+ if (mxc_edid_read(dvi->client->adapter, dvi->client->addr,
+ dvi->edid, &dvi->edid_cfg, dvi->fbi) < 0)
+ dev_warn(&dvi->client->dev, "Can not read edid\n");
+ else if (dvi->fbi->monspecs.modedb_len > 0) {
+ int i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+
+ for (i = 0; i < dvi->fbi->monspecs.modedb_len; i++) {
+ /*FIXME now we do not support interlaced mode */
+ if (!(dvi->fbi->monspecs.modedb[i].vmode
+ & FB_VMODE_INTERLACED))
+ fb_add_videomode(
+ &dvi->fbi->monspecs.modedb[i],
+ &dvi->fbi->modelist);
+ }
+
+ fb_find_mode(&dvi->fbi->var, dvi->fbi, setting->dft_mode_str,
+ NULL, 0, NULL, setting->default_bpp);
+
+ fb_var_to_videomode(&m, &dvi->fbi->var);
+ mode = fb_find_nearest_mode(&m,
+ &dvi->fbi->modelist);
+ fb_videomode_to_var(&dvi->fbi->var, mode);
+ found = 1;
+ }
+ } else
+ dvi->cable_plugin = 0;
+
+ if (!found) {
+ ret = fb_find_mode(&dvi->fbi->var, dvi->fbi, setting->dft_mode_str,
+ NULL, 0, NULL, setting->default_bpp);
+ if (!ret)
+ return -EINVAL;
+ }
+ }
+
+ /* cable detection */
+ if (dvi->client->irq) {
+ ret = request_irq(dvi->client->irq, mxc_dvi_detect_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "dvi_det", dvi);
+ if (ret < 0) {
+ dev_warn(&dvi->client->dev,
+ "MXC dvi: cound not request det irq %d\n",
+ dvi->client->irq);
+ goto err;
+ } else {
+ INIT_DELAYED_WORK(&(dvi->det_work), det_worker);
+ ret = device_create_file(&dvi->pdev->dev, &dev_attr_fb_name);
+ if (ret < 0)
+ dev_warn(&dvi->client->dev,
+ "MXC dvi: cound not create sys node for fb name\n");
+ ret = device_create_file(&dvi->pdev->dev, &dev_attr_cable_state);
+ if (ret < 0)
+ dev_warn(&dvi->client->dev,
+ "MXC dvi: cound not create sys node for cable state\n");
+ ret = device_create_file(&dvi->pdev->dev, &dev_attr_edid);
+ if (ret < 0)
+ dev_warn(&dvi->client->dev,
+ "MXC dvi: cound not create sys node for edid\n");
+
+ dev_set_drvdata(&dvi->pdev->dev, dvi);
+ }
+ }
+
+err:
+ return ret;
+}
+
+static void dvi_deinit(struct mxc_dispdrv_entry *disp)
+{
+ struct mxc_dvi_data *dvi = mxc_dispdrv_getdata(disp);
+
+ if (!IS_ERR(dvi->analog_reg))
+ regulator_disable(dvi->analog_reg);
+
+ free_irq(dvi->client->irq, dvi);
+}
+
+static struct mxc_dispdrv_driver dvi_drv = {
+ .name = DISPDRV_DVI,
+ .init = dvi_init,
+ .deinit = dvi_deinit,
+};
+
+static int __devinit mxc_dvi_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mxc_dvi_data *dvi;
+ int ret = 0;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+
+ dvi = kzalloc(sizeof(struct mxc_dvi_data), GFP_KERNEL);
+ if (!dvi) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ dvi->pdev = platform_device_register_simple("mxc_dvi", 0, NULL, 0);
+ if (IS_ERR(dvi->pdev)) {
+ printk(KERN_ERR
+ "Unable to register MXC DVI as a platform device\n");
+ ret = PTR_ERR(dvi->pdev);
+ goto pdev_reg_failed;
+ }
+
+ dvi->client = client;
+ dvi->disp_dvi = mxc_dispdrv_register(&dvi_drv);
+ mxc_dispdrv_setdata(dvi->disp_dvi, dvi);
+
+ i2c_set_clientdata(client, dvi);
+
+ return ret;
+
+pdev_reg_failed:
+ kfree(dvi);
+alloc_failed:
+ return ret;
+}
+
+static int __devexit mxc_dvi_remove(struct i2c_client *client)
+{
+ struct mxc_dvi_data *dvi = i2c_get_clientdata(client);
+
+ mxc_dispdrv_unregister(dvi->disp_dvi);
+ platform_device_unregister(dvi->pdev);
+ kfree(dvi);
+ return 0;
+}
+
+static const struct i2c_device_id mxc_dvi_id[] = {
+ { "mxc_dvi", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mxc_dvi_id);
+
+static struct i2c_driver mxc_dvi_i2c_driver = {
+ .driver = {
+ .name = "mxc_dvi",
+ },
+ .probe = mxc_dvi_probe,
+ .remove = mxc_dvi_remove,
+ .id_table = mxc_dvi_id,
+};
+
+static int __init mxc_dvi_init(void)
+{
+ return i2c_add_driver(&mxc_dvi_i2c_driver);
+}
+
+static void __exit mxc_dvi_exit(void)
+{
+ i2c_del_driver(&mxc_dvi_i2c_driver);
+}
+
+module_init(mxc_dvi_init);
+module_exit(mxc_dvi_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC DVI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mxc/mxc_edid.c b/drivers/video/mxc/mxc_edid.c
index 9a6add26444..898a3028c30 100644
--- a/drivers/video/mxc/mxc_edid.c
+++ b/drivers/video/mxc/mxc_edid.c
@@ -28,7 +28,8 @@
*/
#include <linux/i2c.h>
#include <linux/fb.h>
-#include "mxc_edid.h"
+#include <linux/export.h>
+#include <mach/mxc_edid.h>
#include "../edid.h"
#undef DEBUG /* define this for verbose EDID parsing output */
@@ -40,80 +41,120 @@
#endif
const struct fb_videomode mxc_cea_mode[64] = {
- /* #1: 640x480p@59.94/60Hz */
+ /* #1: 640x480p@59.94/60Hz 4:3 */
[1] = {
NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
},
- /* #3: 720x480p@59.94/60Hz */
+ /* #2: 720x480p@59.94/60Hz 4:3 */
+ [2] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #3: 720x480p@59.94/60Hz 16:9 */
[3] = {
NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
- /* #4: 1280x720p@59.94/60Hz */
+ /* #4: 1280x720p@59.94/60Hz 16:9 */
[4] = {
NULL, 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
},
- /* #5: 1920x1080i@59.94/60Hz */
+ /* #5: 1920x1080i@59.94/60Hz 16:9 */
[5] = {
NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_INTERLACED, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #6: 720(1440)x480iH@59.94/60Hz 4:3 */
+ [6] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_4_3, 0,
},
- /* #7: 720(1440)x480iH@59.94/60Hz */
+ /* #7: 720(1440)x480iH@59.94/60Hz 16:9 */
[7] = {
NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
- FB_VMODE_INTERLACED, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
- /* #9: 720(1440)x240pH@59.94/60Hz */
+ /* #8: 720(1440)x240pH@59.94/60Hz 4:3 */
+ [8] = {
+ NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #9: 720(1440)x240pH@59.94/60Hz 16:9 */
[9] = {
NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
- /* #16: 1920x1080p@60Hz */
+ /* #16: 1920x1080p@60Hz 16:9 */
[16] = {
NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #17: 720x576pH@50Hz 4:3 */
+ [17] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
},
- /* #18: 720x576pH@50Hz */
+ /* #18: 720x576pH@50Hz 16:9 */
[18] = {
NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
/* #19: 1280x720p@50Hz */
[19] = {
NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
/* #20: 1920x1080i@50Hz */
[20] = {
NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_INTERLACED, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
/* #31: 1920x1080p@50Hz */
[31] = {
NULL, 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
/* #32: 1920x1080p@23.98/24Hz */
[32] = {
NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
},
/* #35: (2880)x480p4x@59.94/60Hz */
[35] = {
NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
- FB_VMODE_NONINTERLACED, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
},
};
+/*
+ * We have a special version of fb_mode_is_equal that ignores
+ * pixclock, since for many CEA modes, 2 frequencies are supported
+ * e.g. 640x480 @ 60Hz or 59.94Hz
+ */
+int mxc_edid_fb_mode_is_equal(const struct fb_videomode *mode1,
+ const struct fb_videomode *mode2)
+{
+ return (mode1->xres == mode2->xres &&
+ mode1->yres == mode2->yres &&
+ mode1->hsync_len == mode2->hsync_len &&
+ mode1->vsync_len == mode2->vsync_len &&
+ mode1->left_margin == mode2->left_margin &&
+ mode1->right_margin == mode2->right_margin &&
+ mode1->upper_margin == mode2->upper_margin &&
+ mode1->lower_margin == mode2->lower_margin &&
+ mode1->sync == mode2->sync &&
+ mode1->vmode == mode2->vmode);
+}
+
static void get_detailed_timing(unsigned char *block,
struct fb_videomode *mode)
{
@@ -303,29 +344,9 @@ int mxc_edid_parse_ext_blk(unsigned char *edid,
return 0;
}
-static char compal_edid[256] = {
-0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0xA3, 0x75, 0x67, 0x01, 0x01, 0x01, 0x01,
-0x02, 0x13, 0x01, 0x03, 0x80, 0x33, 0x1D, 0x78, 0xEA, 0xEE, 0x95, 0xA3, 0x54, 0x4C, 0x99, 0x26,
-0x0F, 0x50, 0x54, 0xBD, 0xEF, 0x80, 0x71, 0x4F, 0x81, 0x4F, 0x90, 0x40, 0x81, 0xC0, 0x81, 0x80,
-0x95, 0x00, 0xB3, 0x00, 0x01, 0x01, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
-0x45, 0x00, 0xFD, 0x1E, 0x11, 0x00, 0x00, 0x1E, 0x66, 0x21, 0x56, 0xAA, 0x51, 0x00, 0x1E, 0x30,
-0x46, 0x8F, 0x33, 0x00, 0xFE, 0x1F, 0x11, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x37,
-0x4C, 0x1E, 0x53, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,
-0x00, 0x46, 0x32, 0x33, 0x57, 0x31, 0x41, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x32,
-0x02, 0x03, 0x24, 0x71, 0x4A, 0x90, 0x05, 0x04, 0x03, 0x07, 0x1F, 0x14, 0x13, 0x12, 0x16, 0x23,
-0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6C, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0xC0,
-0x15, 0x15, 0x1F, 0x1F, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C, 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00,
-0xFE, 0x1F, 0x11, 0x00, 0x00, 0x9E, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28,
-0x55, 0x00, 0xFE, 0x1F, 0x11, 0x00, 0x00, 0x1E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10,
-0x10, 0x3E, 0x96, 0x00, 0xFE, 0x1F, 0x11, 0x00, 0x00, 0x18, 0x8C, 0x0A, 0xA0, 0x14, 0x51, 0xF0,
-0x16, 0x00, 0x26, 0x7C, 0x43, 0x00, 0xFE, 0x1F, 0x11, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3,
-};
-
static int mxc_edid_readblk(struct i2c_adapter *adp,
unsigned short addr, unsigned char *edid)
{
-#if 0
int ret = 0, extblknum = 0;
unsigned char regaddr = 0x0;
struct i2c_msg msg[2] = {
@@ -365,10 +386,6 @@ static int mxc_edid_readblk(struct i2c_adapter *adp,
}
return extblknum;
-#else
- memcpy(edid, compal_edid, 256);
- return 1;
-#endif
}
static int mxc_edid_readsegblk(struct i2c_adapter *adp, unsigned short addr,
@@ -422,7 +439,7 @@ int mxc_edid_var_to_vic(struct fb_var_screeninfo *var)
for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
fb_var_to_videomode(&m, var);
- if (fb_mode_is_equal(&m, &mxc_cea_mode[i]))
+ if (mxc_edid_fb_mode_is_equal(&m, &mxc_cea_mode[i]))
break;
}
@@ -431,8 +448,25 @@ int mxc_edid_var_to_vic(struct fb_var_screeninfo *var)
return i;
}
+
EXPORT_SYMBOL(mxc_edid_var_to_vic);
+int mxc_edid_mode_to_vic(const struct fb_videomode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
+ if (mxc_edid_fb_mode_is_equal(mode, &mxc_cea_mode[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(mxc_cea_mode))
+ return 0;
+
+ return i;
+}
+EXPORT_SYMBOL(mxc_edid_mode_to_vic);
+
/* make sure edid has 512 bytes*/
int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr,
unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi)
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index f21a0d0cbcb..63807917350 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -84,7 +84,7 @@ struct mxcfb_info {
u32 pseudo_palette[16];
bool mode_found;
- bool wait4vsync;
+ volatile bool wait4vsync;
struct semaphore flip_sem;
struct semaphore alpha_flip_sem;
struct completion vsync_complete;
@@ -170,7 +170,7 @@ static int mxcfb_set_fix(struct fb_info *info)
fix->type = FB_TYPE_PACKED_PIXELS;
fix->accel = FB_ACCEL_NONE;
fix->visual = FB_VISUAL_TRUECOLOR;
- fix->xpanstep = 0;
+ fix->xpanstep = 1;
fix->ywrapstep = 1;
fix->ypanstep = 1;
@@ -232,8 +232,7 @@ static int _setup_disp_channel2(struct fb_info *fbi)
}
fbi->var.xoffset = 0;
- base = (fbi->var.yoffset * fbi->var.xres_virtual + fbi->var.xoffset);
- base = (fbi->var.bits_per_pixel) * base / 8;
+ base = (fbi->var.yoffset * fb_stride + fbi->var.xoffset);
base += fbi->fix.smem_start;
retval = ipu_init_channel_buffer(mxc_fbi->ipu,
@@ -241,11 +240,11 @@ static int _setup_disp_channel2(struct fb_info *fbi)
bpp_to_pixfmt(fbi),
fbi->var.xres, fbi->var.yres,
fb_stride,
- IPU_ROTATE_NONE,
+ fbi->var.rotate,
base,
base,
- (fbi->var.accel_flags ==
- FB_ACCEL_TRIPLE_FLAG) ? base : 0,
+ fbi->var.accel_flags &
+ FB_ACCEL_DOUBLE_FLAG ? 0 : base,
0, 0);
if (retval) {
dev_err(fbi->device,
@@ -259,7 +258,7 @@ static int _setup_disp_channel2(struct fb_info *fbi)
IPU_PIX_FMT_GENERIC,
fbi->var.xres, fbi->var.yres,
fbi->var.xres,
- IPU_ROTATE_NONE,
+ fbi->var.rotate,
mxc_fbi->alpha_phy_addr1,
mxc_fbi->alpha_phy_addr0,
0,
@@ -574,11 +573,13 @@ static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->yres = bg_yres - pos_y;
}
+ if (var->rotate > IPU_ROTATE_VERT_FLIP)
+ var->rotate = IPU_ROTATE_NONE;
+
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
- /* Default Y virtual size is 3*yres */
- if (var->yres_virtual < var->yres * 3)
+ if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres * 3;
if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
@@ -929,7 +930,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
init_completion(&mxc_fbi->vsync_complete);
ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
- mxc_fbi->wait4vsync = 1;
+ mxc_fbi->wait4vsync = true;
ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
retval = wait_for_completion_interruptible_timeout(
&mxc_fbi->vsync_complete, 1 * HZ);
@@ -937,7 +938,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
dev_err(fbi->device,
"MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
retval);
- mxc_fbi->wait4vsync = 0;
+ mxc_fbi->wait4vsync = false;
retval = -ETIME;
} else if (retval > 0) {
retval = 0;
@@ -1030,17 +1031,20 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
- if (bg_fbi->var.xres < fbi->var.xres)
- pos.x = 0;
- else
- pos.x = bg_fbi->var.xres - fbi->var.xres;
- }
- if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
- if (bg_fbi->var.yres < fbi->var.yres)
- pos.y = 0;
- else
- pos.y = bg_fbi->var.yres - fbi->var.yres;
+ /* if fb is unblank, check if the pos fit the display */
+ if (mxc_fbi->cur_blank == FB_BLANK_UNBLANK) {
+ if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
+ if (bg_fbi->var.xres < fbi->var.xres)
+ pos.x = 0;
+ else
+ pos.x = bg_fbi->var.xres - fbi->var.xres;
+ }
+ if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
+ if (bg_fbi->var.yres < fbi->var.yres)
+ pos.y = 0;
+ else
+ pos.y = bg_fbi->var.yres - fbi->var.yres;
+ }
}
retval = ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch,
@@ -1153,6 +1157,7 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
u_int y_bottom;
unsigned long base, active_alpha_phy_addr = 0;
bool loc_alpha_en = false;
+ int fb_stride;
int i;
if (info->var.yoffset == var->yoffset)
@@ -1182,8 +1187,20 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
if (y_bottom > info->var.yres_virtual)
return -EINVAL;
- base = (var->yoffset * var->xres_virtual + var->xoffset);
- base = (var->bits_per_pixel) * base / 8;
+ switch (bpp_to_pixfmt(info)) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P:
+ fb_stride = info->var.xres_virtual;
+ break;
+ default:
+ fb_stride = info->fix.line_length;
+ }
+
+ base = (var->yoffset * fb_stride + var->xoffset);
base += info->fix.smem_start;
/* Check if DP local alpha is enabled and find the graphic fb */
@@ -1235,6 +1252,17 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
mxc_fbi->cur_ipu_alpha_buf);
}
+ /* update u/v offset */
+ ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER,
+ bpp_to_pixfmt(info),
+ info->var.xres_virtual,
+ info->var.yres_virtual,
+ info->var.xres_virtual,
+ 0, 0,
+ var->yoffset,
+ var->xoffset);
+
ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
mxc_fbi->cur_ipu_buf);
ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
@@ -1348,7 +1376,7 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
if (mxc_fbi->wait4vsync) {
complete(&mxc_fbi->vsync_complete);
ipu_disable_irq(mxc_fbi->ipu, irq);
- mxc_fbi->wait4vsync = 0;
+ mxc_fbi->wait4vsync = false;
} else {
up(&mxc_fbi->flip_sem);
ipu_disable_irq(mxc_fbi->ipu, irq);
@@ -1759,8 +1787,6 @@ static int mxcfb_register(struct fb_info *fbi)
ret = fb_set_var(fbi, &fbi->var);
fbi->flags &= ~FBINFO_MISC_USEREVENT;
console_unlock();
- if (ret < 0)
- goto err2;
if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
console_lock();
diff --git a/drivers/video/mxc/mxc_lcdif.c b/drivers/video/mxc/mxc_lcdif.c
new file mode 100644
index 00000000000..d9d7fa306a8
--- /dev/null
+++ b/drivers/video/mxc/mxc_lcdif.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mxcfb.h>
+#include <linux/fsl_devices.h>
+#include "mxc_dispdrv.h"
+
+struct mxc_lcdif_data {
+ struct platform_device *pdev;
+ struct mxc_dispdrv_entry *disp_lcdif;
+};
+
+#define DISPDRV_LCD "lcd"
+
+static struct fb_videomode lcdif_modedb[] = {
+ {
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
+ /* 800x480 @ 60 Hz , pixel clk @ 32MHz */
+ "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+};
+static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
+
+static int lcdif_init(struct mxc_dispdrv_entry *disp)
+{
+ int ret, i;
+ struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_lcd_platform_data *plat_data
+ = lcdif->pdev->dev.platform_data;
+ struct fb_videomode *modedb = lcdif_modedb;
+ int modedb_sz = lcdif_modedb_sz;
+
+ /* use platform defined ipu/di */
+ setting->dev_id = plat_data->ipu_id;
+ setting->disp_id = plat_data->disp_id;
+
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ modedb, modedb_sz, NULL, setting->default_bpp);
+ if (!ret) {
+ fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
+ setting->if_fmt = plat_data->default_ifmt;
+ }
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &modedb[i])) {
+ fb_add_videomode(&modedb[i],
+ &setting->fbi->modelist);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void lcdif_deinit(struct mxc_dispdrv_entry *disp)
+{
+ /*TODO*/
+}
+
+static struct mxc_dispdrv_driver lcdif_drv = {
+ .name = DISPDRV_LCD,
+ .init = lcdif_init,
+ .deinit = lcdif_deinit,
+};
+
+static int mxc_lcdif_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mxc_lcdif_data *lcdif;
+
+ lcdif = kzalloc(sizeof(struct mxc_lcdif_data), GFP_KERNEL);
+ if (!lcdif) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ lcdif->pdev = pdev;
+ lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv);
+ mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
+
+ dev_set_drvdata(&pdev->dev, lcdif);
+
+alloc_failed:
+ return ret;
+}
+
+static int mxc_lcdif_remove(struct platform_device *pdev)
+{
+ struct mxc_lcdif_data *lcdif = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_unregister(lcdif->disp_lcdif);
+ kfree(lcdif);
+ return 0;
+}
+
+static struct platform_driver mxc_lcdif_driver = {
+ .driver = {
+ .name = "mxc_lcdif",
+ },
+ .probe = mxc_lcdif_probe,
+ .remove = mxc_lcdif_remove,
+};
+
+static int __init mxc_lcdif_init(void)
+{
+ return platform_driver_register(&mxc_lcdif_driver);
+}
+
+static void __exit mxc_lcdif_exit(void)
+{
+ platform_driver_unregister(&mxc_lcdif_driver);
+}
+
+module_init(mxc_lcdif_init);
+module_exit(mxc_lcdif_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX ipuv3 LCD extern port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mxc/mxcfb_sii902x.c b/drivers/video/mxc/mxcfb_sii902x.c
index 17ce8fca68b..f626f649f9c 100644
--- a/drivers/video/mxc/mxcfb_sii902x.c
+++ b/drivers/video/mxc/mxcfb_sii902x.c
@@ -50,7 +50,7 @@
#include <linux/uaccess.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
-#include "mxc_edid.h"
+#include <mach/mxc_edid.h>
#include "mxc_dispdrv.h"
#define DISPDRV_SII "hdmi"
@@ -671,7 +671,11 @@ static void sii902x_setup(struct sii902x_data *sii902x, struct fb_info *fbi)
/* reg 0x0a: set output format to RGB */
sii902x->tpivmode[2] = 0x00;
- if (fbi->var.xres/16 == fbi->var.yres/9)
+ if (fbi->var.vmode & FB_VMODE_ASPECT_16_9)
+ sii902x->aspect_ratio = VMD_ASPECT_RATIO_16x9;
+ else if (fbi->var.vmode & FB_VMODE_ASPECT_4_3)
+ sii902x->aspect_ratio = VMD_ASPECT_RATIO_4x3;
+ else if (fbi->var.xres/16 == fbi->var.yres/9)
sii902x->aspect_ratio = VMD_ASPECT_RATIO_16x9;
else
sii902x->aspect_ratio = VMD_ASPECT_RATIO_4x3;
diff --git a/drivers/video/mxc/tve.c b/drivers/video/mxc/tve.c
index 35b100349fe..3d81ee977f2 100644
--- a/drivers/video/mxc/tve.c
+++ b/drivers/video/mxc/tve.c
@@ -38,7 +38,6 @@
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <mach/hardware.h>
-#include <mach/ipu-v3.h>
#include "mxc_dispdrv.h"
#define TVE_ENABLE (1UL)
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index cb624eaff19..b342652135f 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -316,6 +316,14 @@ struct fsl_mxc_lcd_platform_data {
int disp_id;
};
+struct fsl_mxc_dvi_platform_data {
+ void (*init) (void);
+ int (*update) (void);
+ char *analog_regulator;
+ int ipu_id;
+ int disp_id;
+};
+
struct fsl_mxc_ldb_platform_data {
char *lvds_bg_reg;
u32 ext_ref;