summaryrefslogtreecommitdiff
path: root/drivers/video/omap2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/Kconfig4
-rw-r--r--drivers/video/omap2/displays/Kconfig15
-rw-r--r--drivers/video/omap2/displays/Makefile2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c819
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.c584
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.h281
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c78
-rw-r--r--drivers/video/omap2/displays/panel-taal.c518
-rw-r--r--drivers/video/omap2/dss/Kconfig20
-rw-r--r--drivers/video/omap2/dss/Makefile4
-rw-r--r--drivers/video/omap2/dss/core.c58
-rw-r--r--drivers/video/omap2/dss/dispc.c2386
-rw-r--r--drivers/video/omap2/dss/display.c84
-rw-r--r--drivers/video/omap2/dss/dpi.c123
-rw-r--r--drivers/video/omap2/dss/dsi.c1731
-rw-r--r--drivers/video/omap2/dss/dss.c79
-rw-r--r--drivers/video/omap2/dss/dss.h113
-rw-r--r--drivers/video/omap2/dss/hdmi.c1373
-rw-r--r--drivers/video/omap2/dss/hdmi.h245
-rw-r--r--drivers/video/omap2/dss/manager.c439
-rw-r--r--drivers/video/omap2/dss/overlay.c132
-rw-r--r--drivers/video/omap2/dss/rfbi.c11
-rw-r--r--drivers/video/omap2/dss/sdi.c42
-rw-r--r--drivers/video/omap2/dss/venc.c15
-rw-r--r--drivers/video/omap2/dss/wb.c179
-rw-r--r--drivers/video/omap2/omapfb/Kconfig7
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c5
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c151
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c25
29 files changed, 8190 insertions, 1333 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index d877c361abda..18bb8359c72a 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -3,6 +3,10 @@ config OMAP2_VRAM
config OMAP2_VRFB
bool
+ depends on ARCH_OMAP2 || ARCH_OMAP3
+ default y if FB_OMAP2
+ help
+ OMAP VRFB buffer support is efficient for rotation
source "drivers/video/omap2/dss/Kconfig"
source "drivers/video/omap2/omapfb/Kconfig"
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index dfb57ee50861..45b92f666506 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -17,8 +17,15 @@ config PANEL_SHARP_LQ043T1DG01
tristate "Sharp LQ043T1DG01 LCD Panel"
depends on OMAP2_DSS
help
+
LCD Panel used in TI's OMAP3517 EVM boards
+config PANEL_PICO_DLP
+ tristate "OMAP PICO DLP Panel"
+ depends on OMAP2_DSS
+ help
+ LCD Panel used in TI's SDP4430 and EVM boards
+
config PANEL_TAAL
tristate "Taal DSI Panel"
depends on OMAP2_DSS_DSI
@@ -33,8 +40,14 @@ config PANEL_TOPPOLY_TDO35S
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
- depends on OMAP2_DSS && I2C
+ depends on OMAP2_DSS && SPI
help
LCD Panel used in OMAP3 Pandora
+config PANEL_ACX565AKM
+ tristate "ACX565AKM Panel"
+ depends on OMAP2_DSS_SDI
+ select BACKLIGHT_CLASS_DEVICE
+ help
+ This is the LCD panel used on Nokia N900
endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index e2bb32168dee..eb7945dca099 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -3,5 +3,7 @@ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
+obj-$(CONFIG_PANEL_PICO_DLP) += panel-picodlp.o
obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
+obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
new file mode 100644
index 000000000000..1f8eb70e2937
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -0,0 +1,819 @@
+/*
+ * Support for ACX565AKM LCD Panel used on Nokia N900
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Original Driver Author: Imre Deak <imre.deak@nokia.com>
+ * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <plat/display.h>
+
+#define MIPID_CMD_READ_DISP_ID 0x04
+#define MIPID_CMD_READ_RED 0x06
+#define MIPID_CMD_READ_GREEN 0x07
+#define MIPID_CMD_READ_BLUE 0x08
+#define MIPID_CMD_READ_DISP_STATUS 0x09
+#define MIPID_CMD_RDDSDR 0x0F
+#define MIPID_CMD_SLEEP_IN 0x10
+#define MIPID_CMD_SLEEP_OUT 0x11
+#define MIPID_CMD_DISP_OFF 0x28
+#define MIPID_CMD_DISP_ON 0x29
+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
+
+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
+
+#define MIPID_CMD_READ_CTRL_DISP 0x54
+#define MIPID_CMD_WRITE_CABC 0x55
+#define MIPID_CMD_READ_CABC 0x56
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+#define MIPID_VER_L4F00311 8
+#define MIPID_VER_ACX565AKM 9
+
+struct acx565akm_device {
+ char *name;
+ int enabled;
+ int model;
+ int revision;
+ u8 display_id[3];
+ unsigned has_bc:1;
+ unsigned has_cabc:1;
+ unsigned cabc_mode;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ struct spi_device *spi;
+ struct mutex mutex;
+
+ struct omap_dss_device *dssdev;
+ struct backlight_device *bl_dev;
+};
+
+static struct acx565akm_device acx_dev;
+static int acx565akm_bl_update_status(struct backlight_device *dev);
+
+/*--------------------MIPID interface-----------------------------*/
+
+static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct spi_message m;
+ struct spi_transfer *x, xfer[5];
+ int r;
+
+ BUG_ON(md->spi == NULL);
+
+ spi_message_init(&m);
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ cmd &= 0xff;
+ x->tx_buf = &cmd;
+ x->bits_per_word = 9;
+ x->len = 2;
+
+ if (rlen > 1 && wlen == 0) {
+ /*
+ * Between the command and the response data there is a
+ * dummy clock cycle. Add an extra bit after the command
+ * word to account for this.
+ */
+ x->bits_per_word = 10;
+ cmd <<= 1;
+ }
+ spi_message_add_tail(x, &m);
+
+ if (wlen) {
+ x++;
+ x->tx_buf = wbuf;
+ x->len = wlen;
+ x->bits_per_word = 9;
+ spi_message_add_tail(x, &m);
+ }
+
+ if (rlen) {
+ x++;
+ x->rx_buf = rbuf;
+ x->len = rlen;
+ spi_message_add_tail(x, &m);
+ }
+
+ r = spi_sync(md->spi, &m);
+ if (r < 0)
+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+}
+
+static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
+{
+ acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void acx565akm_write(struct acx565akm_device *md,
+ int reg, const u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void acx565akm_read(struct acx565akm_device *md,
+ int reg, u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct acx565akm_device *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+/*----------------------MIPID wrappers----------------------------*/
+
+static void set_sleep_mode(struct acx565akm_device *md, int on)
+{
+ int cmd;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ /*
+ * We have to keep 120msec between sleep in/out commands.
+ * (8.2.15, 8.2.16).
+ */
+ hw_guard_wait(md);
+ acx565akm_cmd(md, cmd);
+ hw_guard_start(md, 120);
+}
+
+static void set_display_state(struct acx565akm_device *md, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ acx565akm_cmd(md, cmd);
+}
+
+static int panel_enabled(struct acx565akm_device *md)
+{
+ u32 disp_status;
+ int enabled;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&md->spi->dev,
+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int panel_detect(struct acx565akm_device *md)
+{
+ acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ md->display_id[0], md->display_id[1], md->display_id[2]);
+
+ switch (md->display_id[0]) {
+ case 0x10:
+ md->model = MIPID_VER_ACX565AKM;
+ md->name = "acx565akm";
+ md->has_bc = 1;
+ md->has_cabc = 1;
+ break;
+ case 0x29:
+ md->model = MIPID_VER_L4F00311;
+ md->name = "l4f00311";
+ break;
+ case 0x45:
+ md->model = MIPID_VER_LPH8923;
+ md->name = "lph8923";
+ break;
+ case 0x83:
+ md->model = MIPID_VER_LS041Y3;
+ md->name = "ls041y3";
+ break;
+ default:
+ md->name = "unknown";
+ dev_err(&md->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ md->revision = md->display_id[1];
+
+ dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n",
+ md->name, md->revision);
+
+ return 0;
+}
+
+/*----------------------Backlight Control-------------------------*/
+
+static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
+{
+ u16 ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
+ if (enable) {
+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON;
+ } else {
+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON);
+ }
+
+ ctrl |= 1 << 8;
+ acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
+}
+
+static void set_cabc_mode(struct acx565akm_device *md, unsigned mode)
+{
+ u16 cabc_ctrl;
+
+ md->cabc_mode = mode;
+ if (!md->enabled)
+ return;
+ cabc_ctrl = 0;
+ acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
+ cabc_ctrl &= ~3;
+ cabc_ctrl |= (1 << 8) | (mode & 3);
+ acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
+}
+
+static unsigned get_cabc_mode(struct acx565akm_device *md)
+{
+ return md->cabc_mode;
+}
+
+static unsigned get_hw_cabc_mode(struct acx565akm_device *md)
+{
+ u8 cabc_ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
+ return cabc_ctrl & 3;
+}
+
+static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
+{
+ int bv;
+
+ bv = level | (1 << 8);
+ acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
+
+ if (level)
+ enable_backlight_ctrl(md, 1);
+ else
+ enable_backlight_ctrl(md, 0);
+}
+
+static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
+{
+ u8 bv;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
+
+ return bv;
+}
+
+
+static int acx565akm_bl_update_status(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+ int r;
+ int level;
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ level = dev->props.brightness;
+ else
+ level = 0;
+
+ r = 0;
+ if (md->has_bc)
+ acx565akm_set_brightness(md, level);
+ else if (md->dssdev->set_backlight)
+ r = md->dssdev->set_backlight(md->dssdev, level);
+ else
+ r = -ENODEV;
+
+ mutex_unlock(&md->mutex);
+
+ return r;
+}
+
+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+
+ dev_dbg(&dev->dev, "%s\n", __func__);
+
+ if (!md->has_bc && md->dssdev->set_backlight == NULL)
+ return -ENODEV;
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK) {
+ if (md->has_bc)
+ return acx565akm_get_actual_brightness(md);
+ else
+ return dev->props.brightness;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops acx565akm_bl_ops = {
+ .get_brightness = acx565akm_bl_get_intensity,
+ .update_status = acx565akm_bl_update_status,
+};
+
+/*--------------------Auto Brightness control via Sysfs---------------------*/
+
+static const char *cabc_modes[] = {
+ "off", /* always used when CABC is not supported */
+ "ui",
+ "still-image",
+ "moving-image",
+};
+
+static ssize_t show_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ const char *mode_str;
+ int mode;
+ int len;
+
+ if (!md->has_cabc)
+ mode = 0;
+ else
+ mode = get_cabc_mode(md);
+ mode_str = "unknown";
+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
+ mode_str = cabc_modes[mode];
+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
+
+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
+}
+
+static ssize_t store_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
+ const char *mode_str = cabc_modes[i];
+ int cmp_len = strlen(mode_str);
+
+ if (count > 0 && buf[count - 1] == '\n')
+ count--;
+ if (count != cmp_len)
+ continue;
+
+ if (strncmp(buf, mode_str, cmp_len) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cabc_modes))
+ return -EINVAL;
+
+ if (!md->has_cabc && i != 0)
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ set_cabc_mode(md, i);
+ mutex_unlock(&md->mutex);
+
+ return count;
+}
+
+static ssize_t show_cabc_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int len;
+ int i;
+
+ if (!md->has_cabc)
+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
+
+ for (i = 0, len = 0;
+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
+ i ? " " : "", cabc_modes[i],
+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
+
+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
+}
+
+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
+ show_cabc_mode, store_cabc_mode);
+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
+ show_cabc_available_modes, NULL);
+
+static struct attribute *bldev_attrs[] = {
+ &dev_attr_cabc_mode.attr,
+ &dev_attr_cabc_available_modes.attr,
+ NULL,
+};
+
+static struct attribute_group bldev_attr_group = {
+ .attrs = bldev_attrs,
+};
+
+
+/*---------------------------ACX Panel----------------------------*/
+
+static int acx_get_recommended_bpp(struct omap_dss_device *dssdev)
+{
+ return 16;
+}
+
+static struct omap_video_timings acx_panel_timings = {
+ .x_res = 800,
+ .y_res = 480,
+ .pixel_clock = 24000,
+ .hfp = 28,
+ .hsw = 4,
+ .hbp = 24,
+ .vfp = 3,
+ .vsw = 3,
+ .vbp = 4,
+};
+
+static int acx_panel_probe(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct acx565akm_device *md = &acx_dev;
+ struct backlight_device *bldev;
+ int max_brightness, brightness;
+ struct backlight_properties props;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS;
+ /* FIXME AC bias ? */
+ dssdev->panel.timings = acx_panel_timings;
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+ /*
+ * After reset we have to wait 5 msec before the first
+ * command can be sent.
+ */
+ msleep(5);
+
+ md->enabled = panel_enabled(md);
+
+ r = panel_detect(md);
+ if (r) {
+ dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
+ if (!md->enabled && dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ return r;
+ }
+
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = dssdev;
+ mutex_unlock(&acx_dev.mutex);
+
+ if (!md->enabled) {
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ }
+
+ /*------- Backlight control --------*/
+
+ props.fb_blank = FB_BLANK_UNBLANK;
+ props.power = FB_BLANK_UNBLANK;
+
+ bldev = backlight_device_register("acx565akm", &md->spi->dev,
+ md, &acx565akm_bl_ops, &props);
+ md->bl_dev = bldev;
+ if (md->has_cabc) {
+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
+ if (r) {
+ dev_err(&bldev->dev,
+ "%s failed to create sysfs files\n", __func__);
+ backlight_device_unregister(bldev);
+ return r;
+ }
+ md->cabc_mode = get_hw_cabc_mode(md);
+ }
+
+ if (md->has_bc)
+ max_brightness = 255;
+ else
+ max_brightness = dssdev->max_backlight_level;
+
+ if (md->has_bc)
+ brightness = acx565akm_get_actual_brightness(md);
+ else if (dssdev->get_backlight)
+ brightness = dssdev->get_backlight(dssdev);
+ else
+ brightness = 0;
+
+ bldev->props.max_brightness = max_brightness;
+ bldev->props.brightness = brightness;
+
+ acx565akm_bl_update_status(bldev);
+ return 0;
+}
+
+static void acx_panel_remove(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
+ backlight_device_unregister(md->bl_dev);
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = NULL;
+ mutex_unlock(&acx_dev.mutex);
+}
+
+static int acx_panel_power_on(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ r = omapdss_sdi_display_enable(dssdev);
+ if (r) {
+ pr_err("%s sdi enable failed\n", __func__);
+ return r;
+ }
+
+ /*FIXME tweak me */
+ msleep(50);
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto fail;
+ }
+
+ if (md->enabled) {
+ dev_dbg(&md->spi->dev, "panel already enabled\n");
+ mutex_unlock(&md->mutex);
+ return 0;
+ }
+
+ /*
+ * We have to meet all the following delay requirements:
+ * 1. tRW: reset pulse width 10usec (7.12.1)
+ * 2. tRT: reset cancel time 5msec (7.12.1)
+ * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
+ * case (7.6.2)
+ * 4. 120msec before the sleep out command (7.12.1)
+ */
+ msleep(120);
+
+ set_sleep_mode(md, 0);
+ md->enabled = 1;
+
+ /* 5msec between sleep out and the next command. (8.2.16) */
+ msleep(5);
+ set_display_state(md, 1);
+ set_cabc_mode(md, md->cabc_mode);
+
+ mutex_unlock(&md->mutex);
+
+ return acx565akm_bl_update_status(md->bl_dev);
+fail:
+ omapdss_sdi_display_disable(dssdev);
+ return r;
+}
+
+static void acx_panel_power_off(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (!md->enabled) {
+ mutex_unlock(&md->mutex);
+ return;
+ }
+ set_display_state(md, 0);
+ set_sleep_mode(md, 1);
+ md->enabled = 0;
+ /*
+ * We have to provide PCLK,HS,VS signals for 2 frames (worst case
+ * ~50msec) after sending the sleep in command and asserting the
+ * reset signal. We probably could assert the reset w/o the delay
+ * but we still delay to avoid possible artifacts. (7.6.1)
+ */
+ msleep(50);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ /* FIXME need to tweak this delay */
+ msleep(100);
+
+ omapdss_sdi_display_disable(dssdev);
+
+ mutex_unlock(&md->mutex);
+}
+
+static int acx_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static void acx_panel_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int acx_panel_suspend(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int acx_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static void acx_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ int r;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ omapdss_sdi_display_disable(dssdev);
+
+ dssdev->panel.timings = *timings;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ r = omapdss_sdi_display_enable(dssdev);
+ if (r)
+ dev_err(&dssdev->dev, "%s enable failed\n", __func__);
+ }
+}
+
+static void acx_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+
+static int acx_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ return 0;
+}
+
+
+static struct omap_dss_driver acx_panel_driver = {
+ .probe = acx_panel_probe,
+ .remove = acx_panel_remove,
+
+ .enable = acx_panel_enable,
+ .disable = acx_panel_disable,
+ .suspend = acx_panel_suspend,
+ .resume = acx_panel_resume,
+
+ .set_timings = acx_panel_set_timings,
+ .get_timings = acx_panel_get_timings,
+ .check_timings = acx_panel_check_timings,
+
+ .get_recommended_bpp = acx_get_recommended_bpp,
+
+ .driver = {
+ .name = "panel-acx565akm",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*--------------------SPI probe-------------------------*/
+
+static int acx565akm_spi_probe(struct spi_device *spi)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->mode = SPI_MODE_3;
+ md->spi = spi;
+ mutex_init(&md->mutex);
+ dev_set_drvdata(&spi->dev, md);
+
+ omap_dss_register_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static int acx565akm_spi_remove(struct spi_device *spi)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+ omap_dss_unregister_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static struct spi_driver acx565akm_spi_driver = {
+ .driver = {
+ .name = "acx565akm",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = acx565akm_spi_probe,
+ .remove = __devexit_p(acx565akm_spi_remove),
+};
+
+static int __init acx565akm_init(void)
+{
+ return spi_register_driver(&acx565akm_spi_driver);
+}
+
+static void __exit acx565akm_exit(void)
+{
+ spi_unregister_driver(&acx565akm_spi_driver);
+}
+
+module_init(acx565akm_init);
+module_exit(acx565akm_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("acx565akm LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c
new file mode 100644
index 000000000000..76b01e2a73c9
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-picodlp.c
@@ -0,0 +1,584 @@
+/*
+ * pico_i2c_driver.c
+ * pico DLP driver
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Author: mythripk <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <plat/display.h>
+#include<../drivers/video/omap2/dss/dss.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include "panel-picodlp.h"
+#include <linux/slab.h>
+
+
+#define DRIVER_NAME "pico_i2c"
+/* How much data we can put into single write block */
+#define MAX_I2C_WRITE_BLOCK_SIZE 32
+#define PICO_MAJOR 1 /* 2 bits */
+#define PICO_MINOR 1 /* 2 bits */
+#define DSI_DIV2 (0x40C)
+#define DSI_DIV_LCD (16)
+#define DSI_DIV_PCD (0)
+#define DSI_CONTROL2 (0x238)
+
+static int display_control_reg = (0x58000000 + 0x1000);
+void __iomem *dispc_base;
+
+static struct omap_video_timings pico_ls_timings = {
+ .x_res = 864,
+ .y_res = 480,
+ .hsw = 7,
+ .hfp = 11,
+ .hbp = 7,
+
+ .vsw = 2,
+ .vfp = 3,
+ .vbp = 14,
+};
+
+struct pico {
+ struct i2c_client *client;
+ struct mutex xfer_lock;
+ } *sd;
+
+
+static int dlp_read_block(int reg, u8 *data, int len);
+static int pico_i2c_write(int reg, u32 value);
+
+static int dlp_write_block(int reg, const u8 *data, int len)
+{
+ unsigned char wb[MAX_I2C_WRITE_BLOCK_SIZE + 1];
+ struct i2c_msg msg;
+ int r;
+ int i;
+
+ if (len < 1 ||
+ len > MAX_I2C_WRITE_BLOCK_SIZE) {
+ dev_info(&sd->client->dev, "too long syn_write_block len %d\n",
+ len);
+ return -EIO;
+ }
+
+ wb[0] = reg & 0xff;
+
+ for (i = 0; i < len; i++)
+ wb[i + 1] = data[i];
+
+ mutex_lock(&sd->xfer_lock);
+
+ msg.addr = sd->client->addr;
+ msg.flags = 0;
+ msg.len = len + 1;
+ msg.buf = wb;
+
+ r = i2c_transfer(sd->client->adapter, &msg, 1);
+ mutex_unlock(&sd->xfer_lock);
+
+ if (r == 1) {
+ for (i = 0; i < len; i++)
+ dev_info(&sd->client->dev,
+ "addr %x bw 0x%02x[%d]: 0x%02x\n",
+ sd->client->addr, reg + i, i, data[i]);
+ }
+
+
+ if (r == 1)
+ return 0;
+
+ return r;
+}
+
+static int pico_i2c_write(int reg, u32 value)
+{
+ u8 data[4];
+
+ data[0] = (value & 0xFF000000) >> 24;
+ data[1] = (value & 0x00FF0000) >> 16;
+ data[2] = (value & 0x0000FF00) >> 8;
+ data[3] = (value & 0x000000FF);
+
+ return dlp_write_block(reg, data, 4);
+}
+
+static int dlp_read_block(int reg, u8 *data, int len)
+{
+ unsigned char wb[2];
+ struct i2c_msg msg[2];
+ int r;
+ mutex_lock(&sd->xfer_lock);
+ wb[0] = 0x15 & 0xff;
+ wb[1] = reg & 0xff;
+ msg[0].addr = sd->client->addr;
+ msg[0].len = 2;
+ msg[0].flags = 0;
+ msg[0].buf = wb;
+ msg[1].addr = sd->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = data;
+
+ r = i2c_transfer(sd->client->adapter, msg, 2);
+ mutex_unlock(&sd->xfer_lock);
+
+
+ if (r == 2) {
+ int i;
+
+ for (i = 0; i < len; i++)
+ dev_info(&sd->client->dev,
+ "addr %x br 0x%02x[%d]: 0x%02x\n",
+ sd->client->addr, reg + i, i, data[i]);
+ }
+
+
+ if (r == 2)
+ return len;
+
+ return r;
+}
+
+
+static __attribute__ ((unused)) int pico_i2c_read(int reg)
+{
+ int r;
+ u8 data[4];
+ data[1] = data[2] = data[3] = data[0] = 0;
+
+ r = dlp_read_block(reg, data, 4);
+ return (int)data[3] | ((int)(data[2]) << 8) | ((int)(data[1]) << 16) | ((int)(data[0]) << 24);
+}
+
+/*
+ * Configure datapath for splash image operation
+ * @param flash_address - I - splash image to load from flash
+ * @param flash_num_bytes - I - splash image to load from flash
+ * @param CMT_SEQz - I - select mailbox to load data to: 0=sequence/DRC, 1=CMT/splash
+ * @param table_number - I - splash image to load from flash
+ * @return 0 - no errors
+ * 1 - invalid flash address specified
+ * 2 - invalid mailbox specified
+ * 3 - invalid table_number / mailbox combination
+ */
+int dpp2600_flash_dma(int flash_address, int flash_num_bytes, int CMT_SEQz, int table_number)
+
+{
+ int mailbox_address, mailbox_select;
+
+ /* check argument validity */
+ if (flash_address > 0x1fffff)
+ return 1;
+ if (CMT_SEQz > 1)
+ return 2;
+ if ((CMT_SEQz == 0 && table_number > 6) ||
+ (CMT_SEQz == 1 && table_number > 5))
+ return 3;
+ /* set mailbox parameters */
+ if (CMT_SEQz) {
+ mailbox_address = CMT_SPLASH_LUT_START_ADDR;
+ mailbox_select = CMT_SPLASH_LUT_DEST_SELECT;
+ } else {
+ mailbox_address = SEQ_RESET_LUT_START_ADDR;
+ mailbox_select = SEQ_RESET_LUT_DEST_SELECT;
+ }
+
+ /* configure DMA from flash to LUT */
+ pico_i2c_write(PBC_CONTROL, 0);
+ pico_i2c_write(FLASH_START_ADDR, flash_address);
+ pico_i2c_write(FLASH_READ_BYTES, flash_num_bytes);
+ pico_i2c_write(mailbox_address, 0);
+ pico_i2c_write(mailbox_select, table_number);
+ /* transfer control to flash controller */
+ pico_i2c_write(PBC_CONTROL, 1);
+ mdelay(1000);
+ /* return register access to I2c */
+ pico_i2c_write(PBC_CONTROL, 0);
+ /* close LUT access */
+ pico_i2c_write(mailbox_select, 0);
+ return 0;
+}
+
+/* Configure datapath for parallel RGB operation */
+static void dpp2600_config_rgb(void)
+{
+ /* enable video board output drivers */
+ pico_i2c_write(SEQ_CONTROL, 0);
+ pico_i2c_write(ACTGEN_CONTROL, 0x10);
+ pico_i2c_write(SEQUENCE_MODE, SEQ_LOCK);
+ pico_i2c_write(DATA_FORMAT, RGB888);
+ pico_i2c_write(INPUT_RESOLUTION, WVGA_864_LANDSCAPE);
+ pico_i2c_write(INPUT_SOURCE, PARALLEL_RGB);
+ pico_i2c_write(CPU_IF_SYNC_METHOD, 1);
+ /* turn image back on */
+ pico_i2c_write(SEQ_CONTROL, 1);
+}
+
+/*
+ * Configure datapath for splash image operation
+ * @param image_number - I - splash image to load from flash
+ * @return 0 - no errors
+ * 1 - invalid image_number specified
+ */
+int dpp2600_config_splash(int image_number)
+{
+ int address, size, resolution;
+ printk("dpp2600 config splash");
+ resolution = QWVGA_LANDSCAPE;
+ switch (image_number) {
+ case 0:
+ address = SPLASH_0_START_ADDR;
+ size = SPLASH_0_SIZE;
+ break;
+ case 1:
+ address = SPLASH_1_START_ADDR;
+ size = SPLASH_1_SIZE;
+ break;
+ case 2:
+ address = SPLASH_2_START_ADDR;
+ size = SPLASH_2_SIZE;
+ break;
+ case 3:
+ address = SPLASH_3_START_ADDR;
+ size = SPLASH_3_SIZE;
+ break;
+ case 4:
+ address = OPT_SPLASH_0_START_ADDR;
+ size = OPT_SPLASH_0_SIZE;
+ resolution = WVGA_DMD_OPTICAL_TEST;
+ break;
+ default:
+ return 1;
+ };
+ /* configure sequence, data format and resolution */
+ pico_i2c_write(SEQ_CONTROL, 0);
+ pico_i2c_write(SEQUENCE_MODE, SEQ_FREE_RUN);
+ pico_i2c_write(DATA_FORMAT, RGB565);
+ pico_i2c_write(INPUT_RESOLUTION, resolution);
+ pico_i2c_write(INPUT_SOURCE, SPLASH_SCREEN);
+ dpp2600_flash_dma(address, size, 1, SPLASH_LUT);
+ /* turn image back on */
+ pico_i2c_write(SEQ_CONTROL, 1);
+ return 0;
+}
+
+/*
+ * Modify contents of a 32-bit register
+ * @param anAddr Register address
+ * @param aClearMask Any bits set in this mask will be cleared
+ * @param aSetMask Bits to be set after the clear
+ */
+void modify_pico_register(unsigned int Addr, unsigned int ClearMask,
+ unsigned int SetMask)
+{
+ u32 val;
+ val = __raw_readl(Addr);
+ val &= ~(ClearMask);
+ val |= (SetMask);
+ __raw_writel(val, Addr);
+}
+
+/*
+ * Configure datapath for test pattern generator operation
+ *
+ * @param pattern_select - I - color table to load
+ *
+ * @return 0 - no errors
+ * 1 - invalid pattern specified
+ */
+int dpp2600_config_tpg(int pattern_select)
+{
+ if (pattern_select > TPG_ANSI_CHECKERBOARD)
+ return 1;
+ pico_i2c_write(SEQ_CONTROL, 0);
+ pico_i2c_write(INPUT_RESOLUTION, WVGA_854_LANDSCAPE);
+ pico_i2c_write(SEQUENCE_MODE, SEQ_LOCK);
+ pico_i2c_write(TEST_PAT_SELECT, pattern_select);
+ pico_i2c_write(INPUT_SOURCE, 1);
+ pico_i2c_write(SEQ_CONTROL, 1);
+ return 0;
+}
+
+static int pico_i2c_initialize(void)
+{
+
+ mutex_init(&sd->xfer_lock);
+ mdelay(100);
+ /* pico Soft reset */
+ pico_i2c_write(SOFT_RESET, 1);
+ /*Front end reset*/
+ pico_i2c_write(DMD_PARK_TRIGGER, 1);
+ /* write the software version number to a spare register field */
+ pico_i2c_write(MISC_REG, PICO_MAJOR<<2 | PICO_MINOR);
+ pico_i2c_write(SEQ_CONTROL, 0);
+ pico_i2c_write(SEQ_VECTOR, 0x100);
+ pico_i2c_write(DMD_BLOCK_COUNT, 7);
+ pico_i2c_write(DMD_VCC_CONTROL, 0x109);
+ pico_i2c_write(DMD_PARK_PULSE_COUNT, 0xA);
+ pico_i2c_write(DMD_PARK_PULSE_WIDTH, 0xB);
+ pico_i2c_write(DMD_PARK_DELAY, 0x2ED);
+ pico_i2c_write(DMD_SHADOW_ENABLE, 0);
+ /* serial flash common config */
+ pico_i2c_write(FLASH_OPCODE, 0xB);
+ pico_i2c_write(FLASH_DUMMY_BYTES, 1);
+ pico_i2c_write(FLASH_ADDR_BYTES, 3);
+ /* configure DMA from flash to LUT */
+ dpp2600_flash_dma(CMT_LUT_0_START_ADDR, CMT_LUT_0_SIZE, 1, CMT_LUT_ALL);
+ /* SEQ and DRC look-up tables */
+ dpp2600_flash_dma(SEQUENCE_0_START_ADDR, SEQUENCE_0_SIZE, 0, SEQ_SEQ_LUT);
+ dpp2600_flash_dma(DRC_TABLE_0_START_ADDR, DRC_TABLE_0_SIZE, 0, SEQ_DRC_LUT_ALL);
+ /* frame buffer memory controller enable */
+ pico_i2c_write(SDC_ENABLE, 1);
+ /* AGC control */
+ pico_i2c_write(AGC_CTRL, 7);
+ /*CCA */
+ pico_i2c_write(CCA_C1A, 0x100);
+ pico_i2c_write(CCA_C1B, 0x000);
+ pico_i2c_write(CCA_C1C, 0x000);
+ pico_i2c_write(CCA_C2A, 0x000);
+ pico_i2c_write(CCA_C2B, 0x100);
+ pico_i2c_write(CCA_C2C, 0x000);
+ pico_i2c_write(CCA_C3A, 0x000);
+ pico_i2c_write(CCA_C3B, 0x000);
+ pico_i2c_write(CCA_C3C, 0x100);
+ pico_i2c_write(CCA_C7A, 0x100);
+ pico_i2c_write(CCA_C7B, 0x100);
+ pico_i2c_write(CCA_C7C, 0x100);
+ pico_i2c_write(CCA_ENABLE, 1);
+ /* main datapath setup */
+ pico_i2c_write(CPU_IF_MODE, 1);
+ pico_i2c_write(SHORT_FLIP, 1);
+ pico_i2c_write(CURTAIN_CONTROL, 0);
+ /* display Logo splash image */
+ dpp2600_config_splash(1);
+ pico_i2c_write(DMD_PARK_TRIGGER, 0);
+ /* LED PWM and enables */
+ pico_i2c_write(R_DRIVE_CURRENT, 0x298);
+ pico_i2c_write(G_DRIVE_CURRENT, 0x298);
+ pico_i2c_write(B_DRIVE_CURRENT, 0x298);
+ pico_i2c_write(RGB_DRIVER_ENABLE, 7);
+ mdelay(10000);
+ dpp2600_config_rgb();
+ return 0;
+
+
+}
+
+static int pico_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ printk("pico probe called");
+ sd = kzalloc(sizeof(struct pico), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ i2c_set_clientdata(client, sd);
+ sd->client = client;
+ return 0;
+}
+
+static int __exit pico_remove(struct i2c_client *client)
+{
+ struct pico *sd1 = i2c_get_clientdata(client);
+ kfree(sd1);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static const struct i2c_device_id pico_id[] = {
+ { "picoDLP_i2c_driver", 0 },
+ { },
+};
+
+
+static int picoDLP_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ printk("pico DLP init is called ");
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ return r;
+ }
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ return r;
+ }
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable DPI\n");
+ return r;
+ }
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ display_control_reg = (int)dispc_base;
+ /* Specify the Display Controller Logic Clock Divisor*/
+ modify_pico_register(display_control_reg + DSI_DIV2, 0xFF |
+ (0XFF << DSI_DIV_LCD), (1 << DSI_DIV_LCD) | (4 << DSI_DIV_PCD));
+ /* LCD output Enabled */
+ modify_pico_register(display_control_reg + DSI_CONTROL2, (1<<11), 0x00000000);
+ pico_i2c_initialize();
+ return 0;
+
+}
+static void pico_get_resolution(struct omap_dss_device *dssdev,
+ u16 *xres, u16 *yres)
+{
+ *xres = dssdev->panel.timings.x_res;
+ *yres = dssdev->panel.timings.y_res;
+}
+
+static int picoDLP_panel_probe(struct omap_dss_device *dssdev)
+{
+ dssdev->panel.config &= ~((OMAP_DSS_LCD_IPC) | (OMAP_DSS_LCD_IEO));
+ dssdev->panel.config = (OMAP_DSS_LCD_TFT) | (OMAP_DSS_LCD_ONOFF) |
+ (OMAP_DSS_LCD_IHS) |
+ (OMAP_DSS_LCD_IVS) ;
+ dssdev->panel.acb = 0x0;
+ dssdev->panel.timings = pico_ls_timings;
+
+ return 0;
+}
+
+static void picoDLP_panel_remove(struct omap_dss_device *dssdev)
+{
+ return ;
+}
+
+static void picoDLP_panel_disable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ /* Turn of DLP Power */
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ }
+
+ omapdss_dpi_display_disable(dssdev);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+}
+
+static int picoDLP_panel_suspend(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ /* Turn of DLP Power */
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ return r;
+ }
+
+ omapdss_dpi_display_disable(dssdev);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+ return 0;
+}
+
+static int picoDLP_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ printk("pico DLP resume is called ");
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+ r = -EINVAL;
+ return r;
+ }
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ return r;
+ }
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable DPI\n");
+ return r;
+ }
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ display_control_reg = (int)dispc_base;
+ /* Specify the Display Controller Logic Clock Divisor*/
+ modify_pico_register(display_control_reg + DSI_DIV2, 0xFF |
+ (0XFF << DSI_DIV_LCD), (1 << DSI_DIV_LCD) | (4 << DSI_DIV_PCD));
+ /* LCD output Enabled */
+ modify_pico_register(display_control_reg + DSI_CONTROL2, (1<<11), 0x00000000);
+ pico_i2c_initialize();
+ return 0;
+
+}
+
+static struct omap_dss_driver picoDLP_driver = {
+ .probe = picoDLP_panel_probe,
+ .remove = picoDLP_panel_remove,
+ .enable = picoDLP_panel_enable,
+ .disable = picoDLP_panel_disable,
+ .get_resolution = pico_get_resolution,
+ .suspend = picoDLP_panel_suspend,
+ .resume = picoDLP_panel_resume,
+ .driver = {
+ .name = "picoDLP_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct i2c_driver pico_i2c_driver = {
+ .driver = {
+ .name = "pico_i2c_driver",
+ },
+ .probe = pico_probe,
+ .remove = __exit_p(pico_remove),
+ .id_table = pico_id,
+
+};
+
+static int __init pico_i2c_init(void)
+{
+ int r;
+ r = i2c_add_driver(&pico_i2c_driver);
+ if (r < 0) {
+ printk(KERN_WARNING DRIVER_NAME
+ " driver registration failed\n");
+ return r;
+ }
+ omap_dss_register_driver(&picoDLP_driver);
+ return 0;
+}
+
+
+static void __exit pico_i2c_exit(void)
+{
+ i2c_del_driver(&pico_i2c_driver);
+ omap_dss_unregister_driver(&picoDLP_driver);
+}
+
+
+module_init(pico_i2c_init);
+module_exit(pico_i2c_exit);
+
+
+
+MODULE_DESCRIPTION("pico DLP driver");
+MODULE_LICENSE("GPL");
+
+
+
diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h
new file mode 100644
index 000000000000..01c1b9528467
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-picodlp.h
@@ -0,0 +1,281 @@
+#define MAIN_STATUS 0x03
+#define PBC_CONTROL 0x08
+#define INPUT_SOURCE 0x0B
+#define INPUT_RESOLUTION 0x0C
+#define DATA_FORMAT 0x0D
+#define IMG_ROTATION 0x0E
+#define LONG_FLIP 0x0F
+#define SHORT_FLIP 0x10
+#define TEST_PAT_SELECT 0x11
+#define R_DRIVE_CURRENT 0x12
+#define G_DRIVE_CURRENT 0x13
+#define B_DRIVE_CURRENT 0x14
+#define READ_REG_SELECT 0x15
+#define RGB_DRIVER_ENABLE 0x16
+
+#define CPU_IF_MODE 0x18
+#define FRAME_RATE 0x19
+#define CPU_IF_SYNC_METHOD 0x1A
+#define CPU_IF_SOF 0x1B
+#define CPU_IF_EOF 0x1C
+#define CPU_IF_SLEEP 0x1D
+
+#define SEQUENCE_MODE 0x1E
+#define SOFT_RESET 0x1F
+#define FRONT_END_RESET 0x21
+#define AUTO_PWR_ENABLE 0x22
+
+#define VSYNC_LINE_DELAY 0x23
+#define CPU_PI_HORIZ_START 0x24
+#define CPU_PI_VERT_START 0x25
+#define CPU_PI_HORIZ_WIDTH 0x26
+#define CPU_PI_VERT_HEIGHT 0x27
+
+#define PIXEL_MASK_CROP 0x28
+#define CROP_FIRST_LINE 0x29
+#define CROP_LAST_LINE 0x2A
+#define CROP_FIRST_PIXEL 0x2B
+#define CROP_LAST_PIXEL 0x2C
+#define DMD_PARK_TRIGGER 0x2D
+
+#define MISC_REG 0x30
+
+/* AGC registers */
+#define AGC_CTRL 0x50
+#define AGC_CLIPPED_PIXS 0x55
+#define AGC_BRIGHT_PIXS 0x56
+#define AGC_BG_PIXS 0x57
+#define AGC_SAFETY_MARGIN 0x17
+
+/* CCA registers */
+#define CCA_ENABLE 0x5E
+#define CCA_C1A 0x5F
+#define CCA_C1B 0x60
+#define CCA_C1C 0x61
+#define CCA_C2A 0x62
+#define CCA_C2B 0x63
+#define CCA_C2C 0x64
+#define CCA_C3A 0x65
+#define CCA_C3B 0x66
+#define CCA_C3C 0x67
+#define CCA_C7A 0x71
+#define CCA_C7B 0x72
+#define CCA_C7C 0x73
+
+/* registers for DMA operations from flash to DPP2600 LUTs */
+#define FLASH_ADDR_BYTES 0x74
+#define FLASH_DUMMY_BYTES 0x75
+#define FLASH_WRITE_BYTES 0x76
+#define FLASH_READ_BYTES 0x77
+#define FLASH_OPCODE 0x78
+#define FLASH_START_ADDR 0x79
+#define FLASH_DUMMY2 0x7A
+#define FLASH_WRITE_DATA 0x7B
+
+#define TEMPORAL_DITH_DISABLE 0x7E
+#define SEQ_CONTROL 0x82
+#define SEQ_VECTOR 0x83
+#define DMD_BLOCK_COUNT 0x84
+#define DMD_VCC_CONTROL 0x86
+#define DMD_PARK_PULSE_COUNT 0x87
+#define DMD_PARK_PULSE_WIDTH 0x88
+#define DMD_PARK_DELAY 0x89
+#define DMD_SHADOW_ENABLE 0x8E
+#define SEQ_STATUS 0x8F
+#define FLASH_CLOCK_CONTROL 0x98
+#define DMD_PARK 0x2D
+
+#define SDRAM_BIST_ENABLE 0x46
+#define DDR_DRIVER_STRENGTH 0x9A
+#define SDC_ENABLE 0x9D
+#define SDC_BUFF_SWAP_DISABLE 0xA3
+#define CURTAIN_CONTROL 0xA6
+#define DDR_BUS_SWAP_ENABLE 0xA7
+#define DMD_TRC_ENABLE 0xA8
+#define DMD_BUS_SWAP_ENABLE 0xA9
+
+#define ACTGEN_ENABLE 0xAE
+#define ACTGEN_CONTROL 0xAF
+#define ACTGEN_HORIZ_BP 0xB0
+#define ACTGEN_VERT_BP 0xB1
+
+/* LUT access */
+#define CMT_SPLASH_LUT_START_ADDR 0xFA
+#define CMT_SPLASH_LUT_DEST_SELECT 0xFB
+#define CMT_SPLASH_LUT_DATA 0xFC
+#define SEQ_RESET_LUT_START_ADDR 0xFD
+#define SEQ_RESET_LUT_DEST_SELECT 0xFE
+#define SEQ_RESET_LUT_DATA 0xFF
+
+/* input source defines */
+#define PARALLEL_RGB 0
+#define INT_TEST_PATTERN 1
+#define SPLASH_SCREEN 2
+#define CPU_INTF 3
+#define BT656 4
+
+/* input resolution defines */
+#define QVGA_PORTRAIT 0 /* (240h*320v) */
+#define QVGA_LANDSCAPE 1 /* (320h*240v) */
+#define QWVGA_LANDSCAPE 3 /* (427h*240v) */
+#define VGA_PORTRAIT_2_3 4 /* (430h*640v) */
+#define VGA_LANDSCAPE_3_2 5 /* (640h*430v) */
+#define VGA_PORTRAIT 6 /* (480h*640v) */
+#define VGA_LANDSCAPE 7 /* (640h*480v) */
+#define WVGA_720_PORTRAIT 8 /* (480h*720v) */
+#define WVGA_720_LANDSCAPE 9 /* (720h*480v) */
+#define WVGA_752_PORTRAIT 10 /* (480h*752v) */
+#define WVGA_752_LANDSCAPE 11 /* (752h*480v) */
+#define WVGA_800_PORTRAIT 12 /* (480h*800v) */
+#define WVGA_800_LANDSCAPE 13 /* (800h*480v) */
+#define WVGA_852_PORTRAIT 14 /* (480h*852v) */
+#define WVGA_852_LANDSCAPE 15 /* (852h*480v) */
+#define WVGA_853_PORTRAIT 16 /* (480h*853v) */
+#define WVGA_853_LANDSCAPE 17 /* (853h*480v) */
+#define WVGA_854_PORTRAIT 18 /* (480h*854v) */
+#define WVGA_854_LANDSCAPE 19 /* (854h*480v) */
+#define WVGA_864_PORTRAIT 20 /* (480h*864v) */
+#define WVGA_864_LANDSCAPE 21 /* (864h*480v) */
+#define NTSC_LANDSCAPE 23 /* (720h*240v) */
+#define PAL_LANDSCAPE 25 /* (720h*288v) */
+#define VGA_DMD_OPTICAL_TEST 33 /* (456h*684v) */
+#define WVGA_DMD_OPTICAL_TEST 35 /* (608h*684v) */
+
+/* data format defines */
+#define RGB565 0
+#define RGB666 1
+#define RGB888 2
+
+/* test pattern defines */
+#define TPG_CHECKERBOARD 0
+#define TPG_BLACK 1
+#define TPG_WHITE 2
+#define TPG_RED 3
+#define TPG_BLUE 4
+#define TPG_GREEN 5
+#define TPG_VLINES_BLACK 6
+#define TPG_HLINES_BLACK 7
+#define TPG_VLINES_ALT 8
+#define TPG_HLINES_ALT 9
+#define TPG_DIAG_LINES 10
+#define TPG_GREYRAMP_VERT 11
+#define TPG_GREYRAMP_HORIZ 12
+#define TPG_ANSI_CHECKERBOARD 13
+
+/* sequence mode defines */
+#define SEQ_FREE_RUN 0
+#define SEQ_LOCK 1
+
+/* curtain color defines */
+#define CURTAIN_BLACK 0
+#define CURTAIN_RED 1
+#define CURTAIN_GREEN 2
+#define CURTAIN_BLUE 3
+#define CURTAIN_YELLOW 4
+#define CURTAIN_MAGENTA 5
+#define CURTAIN_CYAN 6
+#define CURTAIN_WHITE 7
+
+/* LUT defines */
+#define CMT_LUT_NONE 0
+#define CMT_LUT_GREEN 1
+#define CMT_LUT_RED 2
+#define CMT_LUT_BLUE 3
+#define CMT_LUT_ALL 4
+#define SPLASH_LUT 5
+
+#define SEQ_LUT_NONE 0
+#define SEQ_DRC_LUT_0 1
+#define SEQ_DRC_LUT_1 2
+#define SEQ_DRC_LUT_2 3
+#define SEQ_DRC_LUT_3 4
+#define SEQ_SEQ_LUT 5
+#define SEQ_DRC_LUT_ALL 6
+#define WPC_PROGRAM_LUT 7
+
+/*#define DMA_STATUS BIT8 */
+
+
+#define BITSTREAM_START_ADDR 0x00000000
+#define BITSTREAM_SIZE 0x00040000
+
+#define WPC_FW_0_START_ADDR 0x00040000
+#define WPC_FW_0_SIZE 0x00000ce8
+
+#define SEQUENCE_0_START_ADDR 0x00044000
+#define SEQUENCE_0_SIZE 0x00001000
+
+#define SEQUENCE_1_START_ADDR 0x00045000
+#define SEQUENCE_1_SIZE 0x00000d10
+
+#define SEQUENCE_2_START_ADDR 0x00046000
+#define SEQUENCE_2_SIZE 0x00000d10
+
+#define SEQUENCE_3_START_ADDR 0x00047000
+#define SEQUENCE_3_SIZE 0x00000d10
+
+#define SEQUENCE_4_START_ADDR 0x00048000
+#define SEQUENCE_4_SIZE 0x00000d10
+
+#define SEQUENCE_5_START_ADDR 0x00049000
+#define SEQUENCE_5_SIZE 0x00000d10
+
+#define SEQUENCE_6_START_ADDR 0x0004a000
+#define SEQUENCE_6_SIZE 0x00000d10
+
+#define CMT_LUT_0_START_ADDR 0x0004b200
+#define CMT_LUT_0_SIZE 0x00000600
+
+#define CMT_LUT_1_START_ADDR 0x0004b800
+#define CMT_LUT_1_SIZE 0x00000600
+
+#define CMT_LUT_2_START_ADDR 0x0004be00
+#define CMT_LUT_2_SIZE 0x00000600
+
+#define CMT_LUT_3_START_ADDR 0x0004c400
+#define CMT_LUT_3_SIZE 0x00000600
+
+#define CMT_LUT_4_START_ADDR 0x0004ca00
+#define CMT_LUT_4_SIZE 0x00000600
+
+#define CMT_LUT_5_START_ADDR 0x0004d000
+#define CMT_LUT_5_SIZE 0x00000600
+
+#define CMT_LUT_6_START_ADDR 0x0004d600
+#define CMT_LUT_6_SIZE 0x00000600
+
+#define DRC_TABLE_0_START_ADDR 0x0004dc00
+#define DRC_TABLE_0_SIZE 0x00000100
+
+#define SPLASH_0_START_ADDR 0x0004dd00
+#define SPLASH_0_SIZE 0x00032280
+
+#define SEQUENCE_7_START_ADDR 0x00080000
+#define SEQUENCE_7_SIZE 0x00000d10
+
+#define SEQUENCE_8_START_ADDR 0x00081800
+#define SEQUENCE_8_SIZE 0x00000d10
+
+#define SEQUENCE_9_START_ADDR 0x00083000
+#define SEQUENCE_9_SIZE 0x00000d10
+
+#define CMT_LUT_7_START_ADDR 0x0008e000
+#define CMT_LUT_7_SIZE 0x00000600
+
+#define CMT_LUT_8_START_ADDR 0x0008e800
+#define CMT_LUT_8_SIZE 0x00000600
+
+#define CMT_LUT_9_START_ADDR 0x0008f000
+#define CMT_LUT_9_SIZE 0x00000600
+
+#define SPLASH_1_START_ADDR 0x0009a000
+#define SPLASH_1_SIZE 0x00032280
+
+#define SPLASH_2_START_ADDR 0x000cd000
+#define SPLASH_2_SIZE 0x00032280
+
+#define SPLASH_3_START_ADDR 0x00100000
+#define SPLASH_3_SIZE 0x00032280
+
+#define OPT_SPLASH_0_START_ADDR 0x00134000
+#define OPT_SPLASH_0_SIZE 0x000cb100
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index 8d51a5e6341c..7d9eb2b1f5af 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -20,10 +20,17 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <plat/display.h>
+struct sharp_data {
+ struct backlight_device *bl;
+};
+
static struct omap_video_timings sharp_ls_timings = {
.x_res = 480,
.y_res = 640,
@@ -39,18 +46,89 @@ static struct omap_video_timings sharp_ls_timings = {
.vbp = 1,
};
+static int sharp_ls_bl_update_status(struct backlight_device *bl)
+{
+ struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
+ int level;
+
+ if (!dssdev->set_backlight)
+ return -EINVAL;
+
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ level = bl->props.brightness;
+ else
+ level = 0;
+
+ return dssdev->set_backlight(dssdev, level);
+}
+
+static int sharp_ls_bl_get_brightness(struct backlight_device *bl)
+{
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ return bl->props.brightness;
+
+ return 0;
+}
+
+static const struct backlight_ops sharp_ls_bl_ops = {
+ .get_brightness = sharp_ls_bl_get_brightness,
+ .update_status = sharp_ls_bl_update_status,
+};
+
+
+
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+ struct sharp_data *sd;
+ int r;
+
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.acb = 0x28;
dssdev->panel.timings = sharp_ls_timings;
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dssdev->dev, sd);
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = dssdev->max_backlight_level;
+
+ bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev,
+ &sharp_ls_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ r = PTR_ERR(bl);
+ kfree(sd);
+ return r;
+ }
+ sd->bl = bl;
+
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.brightness = dssdev->max_backlight_level;
+ r = sharp_ls_bl_update_status(bl);
+ if (r < 0)
+ dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
return 0;
}
static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
{
+ struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
+ struct backlight_device *bl = sd->bl;
+
+ bl->props.power = FB_BLANK_POWERDOWN;
+ sharp_ls_bl_update_status(bl);
+ backlight_device_unregister(bl);
+
+ kfree(sd);
}
static int sharp_ls_power_on(struct omap_dss_device *dssdev)
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 4f3988a41082..9d4115df7782 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -31,6 +31,7 @@
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <plat/display.h>
@@ -64,9 +65,17 @@
/* #define TAAL_USE_ESD_CHECK */
#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
+static bool dsi_te_sync = 1;
+module_param_named(dsi_te_sync, dsi_te_sync, bool, 0644);
+MODULE_PARM_DESC(dsi_te_sync, "enable/disable tearing");
+
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
+static int taal_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h);
struct taal_data {
+ struct mutex lock;
+
struct backlight_device *bldev;
unsigned long hw_guard_end; /* next value of jiffies when we can
@@ -113,12 +122,12 @@ static void hw_guard_wait(struct taal_data *td)
}
}
-static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
+static int taal_dcs_read_1(enum omap_dsi_index ix, u8 dcs_cmd, u8 *data)
{
int r;
u8 buf[1];
- r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
+ r = dsi_vc_dcs_read(ix, TCH, dcs_cmd, buf, 1);
if (r < 0)
return r;
@@ -128,20 +137,20 @@ static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
return 0;
}
-static int taal_dcs_write_0(u8 dcs_cmd)
+static int taal_dcs_write_0(enum omap_dsi_index ix, u8 dcs_cmd)
{
- return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
+ return dsi_vc_dcs_write(ix, TCH, &dcs_cmd, 1);
}
-static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
+static int taal_dcs_write_1(enum omap_dsi_index ix, u8 dcs_cmd, u8 param)
{
u8 buf[2];
buf[0] = dcs_cmd;
buf[1] = param;
- return dsi_vc_dcs_write(TCH, buf, 2);
+ return dsi_vc_dcs_write(ix, TCH, buf, 2);
}
-static int taal_sleep_in(struct taal_data *td)
+static int taal_sleep_in(enum omap_dsi_index ix, struct taal_data *td)
{
u8 cmd;
@@ -150,7 +159,7 @@ static int taal_sleep_in(struct taal_data *td)
hw_guard_wait(td);
cmd = DCS_SLEEP_IN;
- r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
+ r = dsi_vc_dcs_write_nosync(ix, TCH, &cmd, 1);
if (r)
return r;
@@ -161,13 +170,13 @@ static int taal_sleep_in(struct taal_data *td)
return 0;
}
-static int taal_sleep_out(struct taal_data *td)
+static int taal_sleep_out(enum omap_dsi_index ix, struct taal_data *td)
{
int r;
hw_guard_wait(td);
- r = taal_dcs_write_0(DCS_SLEEP_OUT);
+ r = taal_dcs_write_0(ix, DCS_SLEEP_OUT);
if (r)
return r;
@@ -178,30 +187,32 @@ static int taal_sleep_out(struct taal_data *td)
return 0;
}
-static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
+static int taal_get_id(enum omap_dsi_index ix,
+ u8 *id1, u8 *id2, u8 *id3)
{
int r;
- r = taal_dcs_read_1(DCS_GET_ID1, id1);
+ r = taal_dcs_read_1(ix, DCS_GET_ID1, id1);
if (r)
return r;
- r = taal_dcs_read_1(DCS_GET_ID2, id2);
+ r = taal_dcs_read_1(ix, DCS_GET_ID2, id2);
if (r)
return r;
- r = taal_dcs_read_1(DCS_GET_ID3, id3);
+ r = taal_dcs_read_1(ix, DCS_GET_ID3, id3);
if (r)
return r;
return 0;
}
-static int taal_set_addr_mode(u8 rotate, bool mirror)
+static int taal_set_addr_mode(enum omap_dsi_index ix,
+ u8 rotate, bool mirror)
{
int r;
u8 mode;
int b5, b6, b7;
- r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
+ r = taal_dcs_read_1(ix, DCS_READ_MADCTL, &mode);
if (r)
return r;
@@ -235,10 +246,11 @@ static int taal_set_addr_mode(u8 rotate, bool mirror)
mode &= ~((1<<7) | (1<<6) | (1<<5));
mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
- return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
+ return taal_dcs_write_1(ix, DCS_MEM_ACC_CTRL, mode);
}
-static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
+static int taal_set_update_window(enum omap_dsi_index ix,
+ u16 x, u16 y, u16 w, u16 h)
{
int r;
u16 x1 = x;
@@ -253,7 +265,7 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
buf[3] = (x2 >> 8) & 0xff;
buf[4] = (x2 >> 0) & 0xff;
- r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+ r = dsi_vc_dcs_write_nosync(ix, TCH, buf, sizeof(buf));
if (r)
return r;
@@ -263,11 +275,11 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
buf[3] = (y2 >> 8) & 0xff;
buf[4] = (y2 >> 0) & 0xff;
- r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+ r = dsi_vc_dcs_write_nosync(ix, TCH, buf, sizeof(buf));
if (r)
return r;
- dsi_vc_send_bta_sync(TCH);
+ dsi_vc_send_bta_sync(ix, TCH);
return r;
}
@@ -278,6 +290,12 @@ static int taal_bl_update_status(struct backlight_device *dev)
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
int level;
+ enum omap_dsi_index ix;
+
+ if (cpu_is_omap44xx())
+ return;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
dev->props.power == FB_BLANK_UNBLANK)
@@ -289,9 +307,9 @@ static int taal_bl_update_status(struct backlight_device *dev)
if (td->use_dsi_bl) {
if (td->enabled) {
- dsi_bus_lock();
- r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
- dsi_bus_unlock();
+ dsi_bus_lock(ix);
+ r = taal_dcs_write_1(ix, DCS_BRIGHTNESS, level);
+ dsi_bus_unlock(ix);
if (r)
return r;
}
@@ -351,6 +369,15 @@ static irqreturn_t taal_te_isr(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t taal_te_isr2(int irq, void *data)
+{
+ struct omap_dss_device *dssdev = data;
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ complete_all(&td->te_completion);
+
+ return IRQ_HANDLED;
+}
+
static ssize_t taal_num_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -358,11 +385,14 @@ static ssize_t taal_num_errors_show(struct device *dev,
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 errors;
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
if (td->enabled) {
- dsi_bus_lock();
- r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
- dsi_bus_unlock();
+ dsi_bus_lock(ix);
+ r = taal_dcs_read_1(ix, DCS_READ_NUM_ERRORS, &errors);
+ dsi_bus_unlock(ix);
} else {
r = -ENODEV;
}
@@ -380,11 +410,14 @@ static ssize_t taal_hw_revision_show(struct device *dev,
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
if (td->enabled) {
- dsi_bus_lock();
- r = taal_get_id(&id1, &id2, &id3);
- dsi_bus_unlock();
+ dsi_bus_lock(ix);
+ r = taal_get_id(ix, &id1, &id2, &id3);
+ dsi_bus_unlock(ix);
} else {
r = -ENODEV;
}
@@ -429,6 +462,9 @@ static ssize_t store_cabc_mode(struct device *dev,
struct omap_dss_device *dssdev = to_dss_device(dev);
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int i;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
if (sysfs_streq(cabc_modes[i], buf))
@@ -439,10 +475,10 @@ static ssize_t store_cabc_mode(struct device *dev,
return -EINVAL;
if (td->enabled) {
- dsi_bus_lock();
+ dsi_bus_lock(ix);
if (!td->cabc_broken)
- taal_dcs_write_1(DCS_WRITE_CABC, i);
- dsi_bus_unlock();
+ taal_dcs_write_1(ix, DCS_WRITE_CABC, i);
+ dsi_bus_unlock(ix);
}
td->cabc_mode = i;
@@ -499,10 +535,12 @@ static int taal_probe(struct omap_dss_device *dssdev)
dev_dbg(&dssdev->dev, "probe\n");
- dssdev->panel.config = OMAP_DSS_LCD_TFT;
+ dssdev->panel.config = OMAP_DSS_LCD_TFT |
+ OMAP_DSS_LCD_ONOFF | OMAP_DSS_LCD_RF;
dssdev->panel.timings = taal_panel_timings;
dssdev->ctrl.pixel_size = 24;
-
+ dssdev->panel.acbi = 0;
+ dssdev->panel.acb = 0;
td = kzalloc(sizeof(*td), GFP_KERNEL);
if (!td) {
r = -ENOMEM;
@@ -510,12 +548,15 @@ static int taal_probe(struct omap_dss_device *dssdev)
}
td->dssdev = dssdev;
+ mutex_init(&td->lock);
+
td->esd_wq = create_singlethread_workqueue("taal_esd");
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
goto err1;
}
+
INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
dev_set_drvdata(&dssdev->dev, td);
@@ -530,8 +571,10 @@ static int taal_probe(struct omap_dss_device *dssdev)
props.max_brightness = 255;
else
props.max_brightness = 127;
- bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
- &taal_bl_ops, &props);
+
+ bldev = backlight_device_register(dssdev->name,
+ &dssdev->dev, dssdev, &taal_bl_ops, &props);
+
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
goto err2;
@@ -548,8 +591,27 @@ static int taal_probe(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ td->te_enabled = true;
+
if (dssdev->phy.dsi.ext_te) {
int gpio = dssdev->phy.dsi.ext_te_gpio;
+ void __iomem *phymux_base = NULL;
+ int val;
+
+ phymux_base = ioremap(0x4A100000, 0x1000);
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD) {
+ val = __raw_readl(phymux_base + 0x90);
+ val = val & 0xFFFFFFE0;
+ val = val | 0x11B;
+ __raw_writel(val, phymux_base + 0x90);
+ } else {
+ val = __raw_readl(phymux_base + 0x94);
+ val = val & 0xFFFFFFE0;
+ val = val | 0x11B;
+ __raw_writel(val, phymux_base + 0x94);
+ }
r = gpio_request(gpio, "taal irq");
if (r) {
@@ -559,10 +621,15 @@ static int taal_probe(struct omap_dss_device *dssdev)
gpio_direction_input(gpio);
- r = request_irq(gpio_to_irq(gpio), taal_te_isr,
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD) {
+ r = request_irq(gpio_to_irq(gpio), taal_te_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "taal vsync", dssdev);
+ } else {
+ r = request_irq(gpio_to_irq(gpio), taal_te_isr2,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "taal vsync", dssdev);
-
+ "taal vsync2", dssdev);
+ }
if (r) {
dev_err(&dssdev->dev, "IRQ request failed\n");
gpio_free(gpio);
@@ -572,6 +639,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
init_completion(&td->te_completion);
td->use_ext_te = true;
+ iounmap(phymux_base);
}
r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
@@ -629,6 +697,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
@@ -639,7 +710,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
/* it seems we have to wait a bit until taal is ready */
msleep(5);
- dsi_bus_lock();
+ dsi_bus_lock(ix);
r = omapdss_dsi_display_enable(dssdev);
if (r) {
@@ -647,13 +718,13 @@ static int taal_power_on(struct omap_dss_device *dssdev)
goto err0;
}
- omapdss_dsi_vc_enable_hs(TCH, false);
+ omapdss_dsi_vc_enable_hs(ix, TCH, false);
- r = taal_sleep_out(td);
+ r = taal_sleep_out(ix, td);
if (r)
goto err;
- r = taal_get_id(&id1, &id2, &id3);
+ r = taal_get_id(ix, &id1, &id2, &id3);
if (r)
goto err;
@@ -661,22 +732,23 @@ static int taal_power_on(struct omap_dss_device *dssdev)
if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
td->cabc_broken = true;
- taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
- taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
+ taal_dcs_write_1(ix, DCS_BRIGHTNESS, 0xff);
+ taal_dcs_write_1(ix, DCS_CTRL_DISPLAY,
+ (1<<2) | (1<<5)); /* BL | BCTRL */
- taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+ taal_dcs_write_1(ix, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
- taal_set_addr_mode(td->rotate, td->mirror);
+ taal_set_addr_mode(ix, td->rotate, td->mirror);
if (!td->cabc_broken)
- taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
+ taal_dcs_write_1(ix, DCS_WRITE_CABC, td->cabc_mode);
- taal_dcs_write_0(DCS_DISPLAY_ON);
+ taal_dcs_write_0(ix, DCS_DISPLAY_ON);
r = _taal_enable_te(dssdev, td->te_enabled);
if (r)
goto err;
-#ifdef TAAL_USE_ESD_CHECK
+#if TAAL_USE_ESD_CHECK
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
#endif
@@ -691,16 +763,15 @@ static int taal_power_on(struct omap_dss_device *dssdev)
td->intro_printed = true;
}
- omapdss_dsi_vc_enable_hs(TCH, true);
+ omapdss_dsi_vc_enable_hs(ix, TCH, true);
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
return 0;
err:
- dsi_bus_unlock();
-
omapdss_dsi_display_disable(dssdev);
err0:
+ dsi_bus_unlock(ix);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
@@ -710,13 +781,16 @@ err0:
static void taal_power_off(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- dsi_bus_lock();
+ dsi_bus_lock(ix);
cancel_delayed_work(&td->esd_work);
- taal_dcs_write_0(DCS_DISPLAY_OFF);
- taal_sleep_in(td);
+ taal_dcs_write_0(ix, DCS_DISPLAY_OFF);
+ taal_sleep_in(ix, td);
/* wait a bit so that the message goes through */
msleep(10);
@@ -728,67 +802,143 @@ static void taal_power_off(struct omap_dss_device *dssdev)
td->enabled = 0;
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
}
static int taal_enable(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+
dev_dbg(&dssdev->dev, "enable\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
r = taal_power_on(dssdev);
if (r)
- return r;
+ goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ mutex_unlock(&td->lock);
+
+ /* auto update for OMAP4 */
+ if (cpu_is_omap44xx())
+ taal_update(dssdev, 0, 0, 864, 480);
+
+ return 0;
+err:
+ dev_dbg(&dssdev->dev, "enable failed\n");
+ mutex_unlock(&td->lock);
return r;
}
static void taal_disable(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
dev_dbg(&dssdev->dev, "disable\n");
+ mutex_lock(&td->lock);
+
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
taal_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+ mutex_unlock(&td->lock);
}
static int taal_suspend(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ int r;
+
+ if (cpu_is_omap44xx())
+ return;
dev_dbg(&dssdev->dev, "suspend\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ goto err;
+ }
taal_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ mutex_unlock(&td->lock);
+
return 0;
+err:
+ mutex_unlock(&td->lock);
+ return r;
}
static int taal_resume(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+
+ if (cpu_is_omap44xx())
+ return;
+
dev_dbg(&dssdev->dev, "resume\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+ r = -EINVAL;
+ goto err;
+ }
r = taal_power_on(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ mutex_unlock(&td->lock);
+
return r;
+err:
+ mutex_unlock(&td->lock);
+ return r;
+}
+
+static int taal_wait_te(struct omap_dss_device *dssdev)
+{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ long wait = msecs_to_jiffies(500);
+
+ if (!td->use_ext_te || !td->te_enabled)
+ return 0;
+
+ INIT_COMPLETION(td->te_completion);
+ wait = wait_for_completion_timeout(&td->te_completion, wait);
+ if (wait == 0) {
+ dev_err(&dssdev->dev, "timeout waiting TE\n");
+ return -ETIME;
+ }
+
+ return 0;
}
static void taal_framedone_cb(int err, void *data)
{
struct omap_dss_device *dssdev = data;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+
dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ /* auto update for OMAP4 */
+ if (cpu_is_omap44xx())
+ taal_update(dssdev, 0, 0, 864, 480);
}
static int taal_update(struct omap_dss_device *dssdev,
@@ -796,10 +946,14 @@ static int taal_update(struct omap_dss_device *dssdev,
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
- dsi_bus_lock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
if (!td->enabled) {
r = 0;
@@ -810,28 +964,45 @@ static int taal_update(struct omap_dss_device *dssdev,
if (r)
goto err;
- r = taal_set_update_window(x, y, w, h);
+ r = taal_set_update_window(ix, x, y, w, h);
if (r)
goto err;
- r = omap_dsi_update(dssdev, TCH, x, y, w, h,
- taal_framedone_cb, dssdev);
+ if (dsi_te_sync && dssdev->phy.dsi.ext_te)
+ dssdev->driver->wait_for_te(dssdev);
+
+ /* We use VC(1) for VideoPort Data and VC(0) for L4 data */
+ if (cpu_is_omap44xx())
+ r = omap_dsi_update(dssdev, 1, x, y, w, h,
+ taal_framedone_cb, dssdev);
+ else
+ r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+ taal_framedone_cb, dssdev);
if (r)
goto err;
/* note: no bus_unlock here. unlock is in framedone_cb */
+ mutex_unlock(&td->lock);
return 0;
err:
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return r;
}
static int taal_sync(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+
dev_dbg(&dssdev->dev, "sync\n");
- dsi_bus_lock();
- dsi_bus_unlock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
dev_dbg(&dssdev->dev, "sync done\n");
@@ -842,13 +1013,16 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
td->te_enabled = enable;
if (enable)
- r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+ r = taal_dcs_write_1(ix, DCS_TEAR_ON, 0);
else
- r = taal_dcs_write_0(DCS_TEAR_OFF);
+ r = taal_dcs_write_0(ix, DCS_TEAR_OFF);
omapdss_dsi_enable_te(dssdev, enable);
@@ -861,13 +1035,19 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- dsi_bus_lock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
r = _taal_enable_te(dssdev, enable);
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return r;
}
@@ -875,89 +1055,126 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
static int taal_get_te(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->te_enabled;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->te_enabled;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
- dsi_bus_lock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
if (td->enabled) {
- r = taal_set_addr_mode(rotate, td->mirror);
+ r = taal_set_addr_mode(ix, rotate, td->mirror);
if (r)
goto err;
}
td->rotate = rotate;
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return 0;
err:
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return r;
}
static u8 taal_get_rotate(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->rotate;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->rotate;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
- dsi_bus_lock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
if (td->enabled) {
- r = taal_set_addr_mode(td->rotate, enable);
+ r = taal_set_addr_mode(ix, td->rotate, enable);
if (r)
goto err;
}
td->mirror = enable;
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return 0;
err:
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return r;
}
static bool taal_get_mirror(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->mirror;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->mirror;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- dsi_bus_lock();
+ mutex_lock(&td->lock);
+ dsi_bus_lock(ix);
- r = taal_dcs_read_1(DCS_GET_ID1, &id1);
+ r = taal_dcs_read_1(ix, DCS_GET_ID1, &id1);
if (r)
goto err;
- r = taal_dcs_read_1(DCS_GET_ID2, &id2);
+ r = taal_dcs_read_1(ix, DCS_GET_ID2, &id2);
if (r)
goto err;
- r = taal_dcs_read_1(DCS_GET_ID3, &id3);
+ r = taal_dcs_read_1(ix, DCS_GET_ID3, &id3);
if (r)
goto err;
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return 0;
err:
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
+ mutex_unlock(&td->lock);
return r;
}
@@ -970,18 +1187,25 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
int plen;
unsigned buf_used = 0;
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ enum omap_dsi_index ix;
- if (!td->enabled)
- return -ENODEV;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
if (size < w * h * 3)
return -ENOMEM;
+ mutex_lock(&td->lock);
+
+ if (!td->enabled) {
+ r = -ENODEV;
+ goto err1;
+ }
+
size = min(w * h * 3,
dssdev->panel.timings.x_res *
dssdev->panel.timings.y_res * 3);
- dsi_bus_lock();
+ dsi_bus_lock(ix);
/* plen 1 or 2 goes into short packet. until checksum error is fixed,
* use short packets. plen 32 works, but bigger packets seem to cause
@@ -991,22 +1215,22 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
else
plen = 2;
- taal_set_update_window(x, y, w, h);
+ taal_set_update_window(ix, x, y, w, h);
- r = dsi_vc_set_max_rx_packet_size(TCH, plen);
+ r = dsi_vc_set_max_rx_packet_size(ix, TCH, plen);
if (r)
- goto err0;
+ goto err2;
while (buf_used < size) {
u8 dcs_cmd = first ? 0x2e : 0x3e;
first = 0;
- r = dsi_vc_dcs_read(TCH, dcs_cmd,
+ r = dsi_vc_dcs_read(ix, TCH, dcs_cmd,
buf + buf_used, size - buf_used);
if (r < 0) {
dev_err(&dssdev->dev, "read error\n");
- goto err;
+ goto err3;
}
buf_used += r;
@@ -1020,16 +1244,18 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
dev_err(&dssdev->dev, "signal pending, "
"aborting memory read\n");
r = -ERESTARTSYS;
- goto err;
+ goto err3;
}
}
r = buf_used;
-err:
- dsi_vc_set_max_rx_packet_size(TCH, 1);
-err0:
- dsi_bus_unlock();
+err3:
+ dsi_vc_set_max_rx_packet_size(ix, TCH, 1);
+err2:
+ dsi_bus_unlock(ix);
+err1:
+ mutex_unlock(&td->lock);
return r;
}
@@ -1040,26 +1266,32 @@ static void taal_esd_work(struct work_struct *work)
struct omap_dss_device *dssdev = td->dssdev;
u8 state1, state2;
int r;
+ enum omap_dsi_index ix;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- if (!td->enabled)
+ mutex_lock(&td->lock);
+
+ if (!td->enabled) {
+ mutex_unlock(&td->lock);
return;
+ }
- dsi_bus_lock();
+ dsi_bus_lock(ix);
- r = taal_dcs_read_1(DCS_RDDSDR, &state1);
+ r = taal_dcs_read_1(ix, DCS_RDDSDR, &state1);
if (r) {
dev_err(&dssdev->dev, "failed to read Taal status\n");
goto err;
}
/* Run self diagnostics */
- r = taal_sleep_out(td);
+ r = taal_sleep_out(ix, td);
if (r) {
dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
goto err;
}
- r = taal_dcs_read_1(DCS_RDDSDR, &state2);
+ r = taal_dcs_read_1(ix, DCS_RDDSDR, &state2);
if (r) {
dev_err(&dssdev->dev, "failed to read Taal status\n");
goto err;
@@ -1075,31 +1307,34 @@ static void taal_esd_work(struct work_struct *work)
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
if (td->use_ext_te && td->te_enabled) {
- r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+ r = taal_dcs_write_1(ix, DCS_TEAR_ON, 0);
if (r)
goto err;
}
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+ mutex_unlock(&td->lock);
return;
err:
dev_err(&dssdev->dev, "performing LCD reset\n");
- taal_disable(dssdev);
- taal_enable(dssdev);
+ taal_power_off(dssdev);
+ taal_power_on(dssdev);
- dsi_bus_unlock();
+ dsi_bus_unlock(ix);
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+
+ mutex_unlock(&td->lock);
}
static int taal_set_update_mode(struct omap_dss_device *dssdev,
enum omap_dss_update_mode mode)
{
- if (mode != OMAP_DSS_UPDATE_MANUAL)
+ if (mode != OMAP_DSS_UPDATE_AUTO)
return -EINVAL;
return 0;
}
@@ -1107,7 +1342,7 @@ static int taal_set_update_mode(struct omap_dss_device *dssdev,
static enum omap_dss_update_mode taal_get_update_mode(
struct omap_dss_device *dssdev)
{
- return OMAP_DSS_UPDATE_MANUAL;
+ return OMAP_DSS_UPDATE_AUTO;
}
static struct omap_dss_driver taal_driver = {
@@ -1130,7 +1365,7 @@ static struct omap_dss_driver taal_driver = {
.enable_te = taal_enable_te,
.get_te = taal_get_te,
-
+ .wait_for_te = taal_wait_te,
.set_rotate = taal_rotate,
.get_rotate = taal_get_rotate,
.set_mirror = taal_mirror,
@@ -1146,9 +1381,48 @@ static struct omap_dss_driver taal_driver = {
},
};
+static struct omap_dss_driver taal2_driver = {
+ .probe = taal_probe,
+ .remove = taal_remove,
+
+ .enable = taal_enable,
+ .disable = taal_disable,
+ .suspend = taal_suspend,
+ .resume = taal_resume,
+
+ .set_update_mode = taal_set_update_mode,
+ .get_update_mode = taal_get_update_mode,
+
+ .update = taal_update,
+ .sync = taal_sync,
+
+ .get_resolution = taal_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .enable_te = taal_enable_te,
+ .get_te = taal_get_te,
+ .wait_for_te = taal_wait_te,
+ .set_rotate = taal_rotate,
+ .get_rotate = taal_get_rotate,
+ .set_mirror = taal_mirror,
+ .get_mirror = taal_get_mirror,
+ .run_test = taal_run_test,
+ .memory_read = taal_memory_read,
+
+ .get_timings = taal_get_timings,
+
+ .driver = {
+ .name = "taal2",
+ .owner = THIS_MODULE,
+ },
+};
+
+
static int __init taal_init(void)
{
omap_dss_register_driver(&taal_driver);
+ if (cpu_is_omap44xx())
+ omap_dss_register_driver(&taal2_driver);
return 0;
}
@@ -1156,6 +1430,8 @@ static int __init taal_init(void)
static void __exit taal_exit(void)
{
omap_dss_unregister_driver(&taal_driver);
+ if (cpu_is_omap44xx())
+ omap_dss_unregister_driver(&taal2_driver);
}
module_init(taal_init);
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index 87afb81b2c44..810586c56968 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -1,8 +1,8 @@
menuconfig OMAP2_DSS
- tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
- depends on ARCH_OMAP2 || ARCH_OMAP3
+ tristate "OMAP2/3/4 Display Subsystem support (EXPERIMENTAL)"
+ depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
help
- OMAP2/3 Display Subsystem support.
+ OMAP2/3/4 Display Subsystem support.
if OMAP2_DSS
@@ -36,6 +36,12 @@ config OMAP2_DSS_COLLECT_IRQ_STATS
<debugfs>/omapdss/dispc_irq for DISPC interrupts, and
<debugfs>/omapdss/dsi_irq for DSI interrupts.
+config OMAP2_DSS_DPI
+ bool "DPI support"
+ default y
+ help
+ DPI Interface. This is the Parallel Display Interface.
+
config OMAP2_DSS_RFBI
bool "RFBI support"
default n
@@ -54,6 +60,12 @@ config OMAP2_DSS_VENC
help
OMAP Video Encoder support for S-Video and composite TV-out.
+config OMAP2_DSS_HDMI
+ bool "HDMI support"
+ default n
+ help
+ OMAP HDMI panel support.
+
config OMAP2_DSS_SDI
bool "SDI support"
depends on ARCH_OMAP3
@@ -66,7 +78,7 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
- depends on ARCH_OMAP3
+ depends on ARCH_OMAP3 || ARCH_OMAP4
default n
help
MIPI DSI (Display Serial Interface) support.
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 980c72c2db98..c1dd777e9727 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,6 +1,8 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o wb.o
+omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
+omapdss-$(CONFIG_OMAP2_DSS_HDMI) += hdmi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 7ebe50b335ed..ed9f76912ae9 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -68,6 +68,11 @@ unsigned int dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
+static int hdmi_code = 16;
+static int hdmi_mode = 1;
+module_param_named(hdmicode, hdmi_code, int, 0644);
+module_param_named(hdmimode, hdmi_mode, int, 0644);
+
/* CONTEXT */
static int dss_get_ctx_id(void)
{
@@ -224,16 +229,19 @@ err:
static void dss_put_clocks(void)
{
+#if 0
if (core.dss_96m_fck)
clk_put(core.dss_96m_fck);
clk_put(core.dss_54m_fck);
clk_put(core.dss1_fck);
clk_put(core.dss2_fck);
clk_put(core.dss_ick);
+#endif
}
unsigned long dss_clk_get_rate(enum dss_clock clk)
{
+#if 0
switch (clk) {
case DSS_CLK_ICK:
return clk_get_rate(core.dss_ick);
@@ -248,7 +256,8 @@ unsigned long dss_clk_get_rate(enum dss_clock clk)
}
BUG();
- return 0;
+#endif
+ return 153600000;
}
static unsigned count_clk_bits(enum dss_clock clks)
@@ -272,7 +281,7 @@ static unsigned count_clk_bits(enum dss_clock clks)
static void dss_clk_enable_no_ctx(enum dss_clock clks)
{
unsigned num_clks = count_clk_bits(clks);
-
+#if 0
if (clks & DSS_CLK_ICK)
clk_enable(core.dss_ick);
if (clks & DSS_CLK_FCK1)
@@ -283,7 +292,7 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks)
clk_enable(core.dss_54m_fck);
if (clks & DSS_CLK_96M)
clk_enable(core.dss_96m_fck);
-
+#endif
core.num_clks_enabled += num_clks;
}
@@ -300,7 +309,7 @@ void dss_clk_enable(enum dss_clock clks)
static void dss_clk_disable_no_ctx(enum dss_clock clks)
{
unsigned num_clks = count_clk_bits(clks);
-
+#if 0
if (clks & DSS_CLK_ICK)
clk_disable(core.dss_ick);
if (clks & DSS_CLK_FCK1)
@@ -311,7 +320,7 @@ static void dss_clk_disable_no_ctx(enum dss_clock clks)
clk_disable(core.dss_54m_fck);
if (clks & DSS_CLK_96M)
clk_disable(core.dss_96m_fck);
-
+#endif
core.num_clks_enabled -= num_clks;
}
@@ -411,7 +420,8 @@ static void dss_debug_dump_clocks(struct seq_file *s)
dss_dump_clocks(s);
dispc_dump_clocks(s);
#ifdef CONFIG_OMAP2_DSS_DSI
- dsi_dump_clocks(s);
+ dsi_dump_clocks(DSI1, s);
+ dsi_dump_clocks(DSI2, s);
#endif
}
@@ -489,7 +499,7 @@ static int omap_dss_probe(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int skip_init = 0;
- int r;
+ int r = 0;
int i;
core.pdev = pdev;
@@ -497,6 +507,10 @@ static int omap_dss_probe(struct platform_device *pdev)
dss_init_overlay_managers(pdev);
dss_init_overlays(pdev);
+ if (cpu_is_omap44xx())
+ dss_init_writeback(pdev); /*Write back init*/
+
+ if (!cpu_is_omap44xx())
r = dss_get_clocks();
if (r)
goto fail0;
@@ -526,11 +540,13 @@ static int omap_dss_probe(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OMAP2_DSS_DPI
r = dpi_init(pdev);
if (r) {
DSSERR("Failed to initialize dpi\n");
goto fail0;
}
+#endif
r = dispc_init();
if (r) {
@@ -552,15 +568,31 @@ static int omap_dss_probe(struct platform_device *pdev)
goto fail0;
}
#endif
+ }
+ if (!cpu_is_omap24xx()) {
#ifdef CONFIG_OMAP2_DSS_DSI
r = dsi_init(pdev);
if (r) {
DSSERR("Failed to initialize DSI\n");
goto fail0;
}
+ if (cpu_is_omap44xx()) {
+ r = dsi2_init(pdev);
+ if (r) {
+ DSSERR("Failed to initialize DSI2\n");
+ goto fail0;
+ }
+ }
#endif
}
+#ifdef CONFIG_OMAP2_DSS_HDMI
+ r = hdmi_init(pdev, hdmi_code, hdmi_mode);
+ if (r) {
+ DSSERR("Failed to initialize hdmi\n");
+ goto fail0;
+ }
+#endif
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
r = dss_initialize_debugfs();
if (r)
@@ -600,17 +632,25 @@ static int omap_dss_remove(struct platform_device *pdev)
#ifdef CONFIG_OMAP2_DSS_VENC
venc_exit();
#endif
+#ifdef CONFIG_OMAP2_DSS_HDMI
+ hdmi_exit();
+#endif
dispc_exit();
+#ifdef CONFIG_OMAP2_DSS_DPI
dpi_exit();
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
rfbi_exit();
#endif
- if (cpu_is_omap34xx()) {
+ if (!cpu_is_omap24xx()) {
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_exit();
+ if (cpu_is_omap44xx())
+ dsi2_exit();
#endif
#ifdef CONFIG_OMAP2_DSS_SDI
- sdi_exit();
+ if (cpu_is_omap34xx())
+ sdi_exit();
#endif
}
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index e777e352dbcd..6b5695f6025a 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -38,14 +38,18 @@
#include <plat/display.h>
#include "dss.h"
+#include <mach/tiler.h>
-/* DISPC */
-#define DISPC_BASE 0x48050400
+#ifndef CONFIG_ARCH_OMAP4
+#define DISPC_BASE 0x48050400
+#else
+#define DISPC_BASE 0x58001000
+#endif
-#define DISPC_SZ_REGS SZ_1K
+#define DISPC_SZ_REGS SZ_16K
struct dispc_reg { u16 idx; };
-
+extern void __iomem *dispc_base;
#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
/* DISPC common */
@@ -67,9 +71,11 @@ struct dispc_reg { u16 idx; };
#define DISPC_TIMING_V DISPC_REG(0x0068)
#define DISPC_POL_FREQ DISPC_REG(0x006C)
#define DISPC_DIVISOR DISPC_REG(0x0070)
+#define DISPC_DIVISOR1 DISPC_REG(0x0804)
#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
#define DISPC_SIZE_DIG DISPC_REG(0x0078)
#define DISPC_SIZE_LCD DISPC_REG(0x007C)
+#define DISPC_GLOBAL_BUFFER DISPC_REG(0x0800)
/* DISPC GFX plane */
#define DISPC_GFX_BA0 DISPC_REG(0x0080)
@@ -130,6 +136,118 @@ struct dispc_reg { u16 idx; };
DISPC_IRQ_SYNC_LOST | \
DISPC_IRQ_SYNC_LOST_DIGIT)
+#define DISPC_CONTROL2 DISPC_REG(0x0238)
+
+/******** registers related to VID3 and WB pipelines ****/
+/* DISPC Video plane, n = 0 for VID3, n = 1 for WB _VID_V3_WB_ */
+#define DISPC_VID_V3_WB_REG(n, idx) DISPC_REG(0x0300 + (n)*0x200 + idx)
+
+#define DISPC_VID_V3_WB_ACCU0(n) DISPC_VID_V3_WB_REG(n, 0x0000)
+#define DISPC_VID_V3_WB_ACCU1(n) DISPC_VID_V3_WB_REG(n, 0x0004)
+
+#define DISPC_VID_V3_WB_BA0(n) DISPC_VID_V3_WB_REG(n, 0x0008)
+#define DISPC_VID_V3_WB_BA1(n) DISPC_VID_V3_WB_REG(n, 0x000C)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_V3_WB_FIR_COEF_H(n, i) DISPC_REG(0x0310+(n)*0x200+(i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_V3_WB_FIR_COEF_HV(n, i) DISPC_REG(0x0314+(n)*0x200+(i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_V3_WB_FIR_COEF_V(n, i) DISPC_REG(0x0350+(n)*0x200+(i)*0x4)
+
+#define DISPC_VID_V3_WB_ATTRIBUTES(n) DISPC_VID_V3_WB_REG(n, 0x0070)
+
+/* coef index i = {0, 1, 2, 3, 4} */
+#define DISPC_VID_V3_WB_CONV_COEF(n, i) DISPC_REG(0x0374 + (n)*0x200 + (i)*0x4)
+
+#define DISPC_VID_V3_WB_BUF_SIZE_STATUS(n) DISPC_VID_V3_WB_REG(n, 0x0088)
+#define DISPC_VID_V3_WB_BUF_THRESHOLD(n) DISPC_VID_V3_WB_REG(n, 0x008C)
+#define DISPC_VID_V3_WB_FIR(n) DISPC_VID_V3_WB_REG(n, 0x0090)
+#define DISPC_VID_V3_WB_PICTURE_SIZE(n) DISPC_VID_V3_WB_REG(n, 0x0094)
+#define DISPC_VID_V3_WB_PIXEL_INC(n) DISPC_VID_V3_WB_REG(n, 0x0098)
+
+#define DISPC_VID_VID3_POSITION DISPC_REG(0x039C)
+#define DISPC_VID_VID3_PRELOAD DISPC_REG(0x03A0)
+
+
+#define DISPC_VID_V3_WB_ROW_INC(n) DISPC_VID_V3_WB_REG(n, 0x00A4)
+#define DISPC_VID_V3_WB_SIZE(n) DISPC_VID_V3_WB_REG(n, 0x00A8)
+
+#define DISPC_VID_V3_WB_FIR2(n) DISPC_REG(0x0724 + (n)*0x6C)
+ /* n=0: VID3, n=1: WB*/
+
+#define DISPC_VID_V3_WB_ACCU2_0(n) DISPC_REG(0x0728 + (n)*0x6C)
+ /* n=0: VID3, n=1: WB*/
+#define DISPC_VID_V3_WB_ACCU2_1(n) DISPC_REG(0x072C + (n)*0x6C)
+ /* n=0: VID3, n=1: WB*/
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} n=0: VID3, n=1: WB */
+#define DISPC_VID_V3_WB_FIR_COEF_H2(n, i) DISPC_REG(0x0730+(n)*0x6C+(i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_V3_WB_FIR_COEF_HV2(n, i) DISPC_REG(0x0734+(n)*0x6C+(i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_V3_WB_FIR_COEF_V2(n, i) DISPC_REG(0x0770+(n)*0x6C+(i)*0x4)
+
+
+/*********End Vid3 and WB Registers ***************/
+
+/********** OMAP4 new global registers **/
+#define DISPC_DEFAULT_COLOR2 DISPC_REG(0x03AC)
+#define DISPC_TRANS_COLOR2 DISPC_REG(0x03B0)
+#define DISPC_CPR2_COEF_B DISPC_REG(0x03B4)
+#define DISPC_CPR2_COEF_G DISPC_REG(0x03B8)
+#define DISPC_CPR2_COEF_R DISPC_REG(0x03BC)
+#define DISPC_DATA2_CYCLE1 DISPC_REG(0x03C0)
+#define DISPC_DATA2_CYCLE2 DISPC_REG(0x03C4)
+#define DISPC_DATA2_CYCLE3 DISPC_REG(0x03C8)
+#define DISPC_SIZE_LCD2 DISPC_REG(0x03CC)
+#define DISPC_TIMING_H2 DISPC_REG(0x0400)
+#define DISPC_TIMING_V2 DISPC_REG(0x0404)
+#define DISPC_POL_FREQ2 DISPC_REG(0x0408)
+#define DISPC_DIVISOR2 DISPC_REG(0x040C)
+/* DISPC Video plane,
+ n = 0 for VID1
+ n = 1 for VID2
+ and n = 2 for VID3,
+ n = 3 for WB*/
+
+#define DISPC_VID_OMAP4_REG(n, idx) DISPC_REG(0x0600 + (n)*0x04 + idx)
+
+#define DISPC_VID_BA_UV0(n) DISPC_VID_OMAP4_REG((n)*2, 0x0000)
+#define DISPC_VID_BA_UV1(n) DISPC_VID_OMAP4_REG((n)*2, 0x0004)
+
+#define DISPC_CONFIG2 DISPC_REG(0x0620)
+
+#define DISPC_VID_ATTRIBUTES2(n) DISPC_VID_OMAP4_REG(n, 0x0024)
+ /* n = {0,1,2,3} */
+#define DISPC_GAMMA_TABLE(n) DISPC_VID_OMAP4_REG(n, 0x0030)
+ /* n = {0,1,2,3} */
+
+/* VID1/VID2 specific new registers */
+#define DISPC_VID_FIR2(n) DISPC_REG(0x063C + (n)*0x6C)
+ /* n=0: VID1, n=1: VID2*/
+
+#define DISPC_VID_ACCU2_0(n) DISPC_REG(0x0640 + (n)*0x6C)
+ /* n=0: VID1, n=1: VID2*/
+#define DISPC_VID_ACCU2_1(n) DISPC_REG(0x0644 + (n)*0x6C)
+ /* n=0: VID1, n=1: VID2*/
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} n=0: VID1, n=1: VID2 */
+#define DISPC_VID_FIR_COEF_H2(n, i) DISPC_REG(0x0648 + (n)*0x6C + (i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_FIR_COEF_HV2(n, i) DISPC_REG(0x064C + (n)*0x6C + (i)*0x8)
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+#define DISPC_VID_FIR_COEF_V2(n, i) DISPC_REG(0x0688 + (n)*0x6C + (i)*0x4)
+/*end of VID1/VID2 specific new registers*/
+
+
+
#define DISPC_MAX_NR_ISRS 8
struct omap_dispc_isr_data {
@@ -146,7 +264,10 @@ struct omap_dispc_isr_data {
static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
DISPC_VID_ATTRIBUTES(0),
- DISPC_VID_ATTRIBUTES(1) };
+ DISPC_VID_ATTRIBUTES(1),
+ DISPC_VID_V3_WB_ATTRIBUTES(0), /* VID 3 pipeline */
+ DISPC_VID_V3_WB_ATTRIBUTES(1)};/* WB pipeline */
+
struct dispc_irq_stats {
unsigned long last_reset;
@@ -185,6 +306,28 @@ static inline u32 dispc_read_reg(const struct dispc_reg idx)
return __raw_readl(dispc.base + idx.idx);
}
+static inline u8 calc_tiler_orientation(u8 rotation, u8 mir)
+{
+ static u8 orientation;
+ switch (rotation) {
+ case 0:
+ orientation = (mir ? 0x2 : 0x0);
+ break;
+ case 1:
+ orientation = (mir ? 0x7 : 0x6);
+ break;
+ case 2:
+ orientation = (mir ? 0x1 : 0x3);
+ break;
+ case 3:
+ orientation = (mir ? 0x4 : 0x5);
+ break;
+ }
+ return orientation;
+}
+
+
+
#define SR(reg) \
dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
#define RR(reg) \
@@ -233,6 +376,214 @@ void dispc_save_context(void)
SR(GFX_PRELOAD);
+ if (cpu_is_omap44xx()) {
+ SR(DIVISOR1);
+ SR(GLOBAL_BUFFER);
+ SR(CONTROL2);
+ SR(DEFAULT_COLOR2);
+ SR(TRANS_COLOR2);
+ SR(CPR2_COEF_B);
+ SR(CPR2_COEF_G);
+ SR(CPR2_COEF_R);
+ SR(DATA2_CYCLE1);
+ SR(DATA2_CYCLE2);
+ SR(DATA2_CYCLE3);
+ SR(SIZE_LCD2);
+ SR(TIMING_H2);
+ SR(TIMING_V2);
+ SR(POL_FREQ2);
+ SR(DIVISOR2);
+
+ SR(CONFIG2);
+
+ /**** VID3 ****/;
+
+ SR(VID_V3_WB_ACCU0(0));
+ SR(VID_V3_WB_ACCU1(0));
+ SR(VID_V3_WB_BA0(0));
+ SR(VID_V3_WB_BA1(0));
+
+ SR(VID_V3_WB_FIR_COEF_H(0, 0));
+ SR(VID_V3_WB_FIR_COEF_H(0, 1));
+ SR(VID_V3_WB_FIR_COEF_H(0, 2));
+ SR(VID_V3_WB_FIR_COEF_H(0, 3));
+ SR(VID_V3_WB_FIR_COEF_H(0, 4));
+ SR(VID_V3_WB_FIR_COEF_H(0, 5));
+ SR(VID_V3_WB_FIR_COEF_H(0, 6));
+ SR(VID_V3_WB_FIR_COEF_H(0, 7));
+
+ SR(VID_V3_WB_FIR_COEF_HV(0, 0));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 1));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 2));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 3));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 4));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 5));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 6));
+ SR(VID_V3_WB_FIR_COEF_HV(0, 7));
+
+ SR(VID_V3_WB_FIR_COEF_V(0, 0));
+ SR(VID_V3_WB_FIR_COEF_V(0, 1));
+ SR(VID_V3_WB_FIR_COEF_V(0, 2));
+ SR(VID_V3_WB_FIR_COEF_V(0, 3));
+ SR(VID_V3_WB_FIR_COEF_V(0, 4));
+ SR(VID_V3_WB_FIR_COEF_V(0, 5));
+ SR(VID_V3_WB_FIR_COEF_V(0, 6));
+ SR(VID_V3_WB_FIR_COEF_V(0, 7));
+
+ SR(VID_V3_WB_ATTRIBUTES(0));
+ SR(VID_V3_WB_CONV_COEF(0, 0));
+ SR(VID_V3_WB_CONV_COEF(0, 1));
+ SR(VID_V3_WB_CONV_COEF(0, 2));
+ SR(VID_V3_WB_CONV_COEF(0, 3));
+ SR(VID_V3_WB_CONV_COEF(0, 4));
+ SR(VID_V3_WB_CONV_COEF(0, 5));
+ SR(VID_V3_WB_CONV_COEF(0, 6));
+ SR(VID_V3_WB_CONV_COEF(0, 7));
+
+ SR(VID_V3_WB_BUF_SIZE_STATUS(0));
+ SR(VID_V3_WB_BUF_THRESHOLD(0));
+ SR(VID_V3_WB_FIR(0));
+ SR(VID_V3_WB_PICTURE_SIZE(0));
+ SR(VID_V3_WB_PIXEL_INC(0));
+ SR(VID_VID3_POSITION);
+ SR(VID_VID3_PRELOAD);
+
+ SR(VID_V3_WB_ROW_INC(0));
+ SR(VID_V3_WB_SIZE(0));
+ SR(VID_V3_WB_FIR2(0));
+ SR(VID_V3_WB_ACCU2_0(0));
+ SR(VID_V3_WB_ACCU2_1(0));
+
+ SR(VID_V3_WB_FIR_COEF_H2(0, 0));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 1));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 2));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 3));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 4));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 5));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 6));
+ SR(VID_V3_WB_FIR_COEF_H2(0, 7));
+
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 0));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 1));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 2));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 3));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 4));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 5));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 6));
+ SR(VID_V3_WB_FIR_COEF_HV2(0, 7));
+
+ SR(VID_V3_WB_FIR_COEF_V2(0, 0));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 1));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 2));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 3));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 4));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 5));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 6));
+ SR(VID_V3_WB_FIR_COEF_V2(0, 7));
+
+ /******* WB Registers *********/;
+
+ SR(VID_V3_WB_ACCU0(1));
+ SR(VID_V3_WB_ACCU1(1));
+ SR(VID_V3_WB_BA0(1));
+ SR(VID_V3_WB_BA1(1));
+
+ SR(VID_V3_WB_FIR_COEF_H(1, 0));
+ SR(VID_V3_WB_FIR_COEF_H(1, 1));
+ SR(VID_V3_WB_FIR_COEF_H(1, 2));
+ SR(VID_V3_WB_FIR_COEF_H(1, 3));
+ SR(VID_V3_WB_FIR_COEF_H(1, 4));
+ SR(VID_V3_WB_FIR_COEF_H(1, 5));
+ SR(VID_V3_WB_FIR_COEF_H(1, 6));
+ SR(VID_V3_WB_FIR_COEF_H(1, 7));
+
+ SR(VID_V3_WB_FIR_COEF_HV(1, 0));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 1));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 2));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 3));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 4));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 5));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 6));
+ SR(VID_V3_WB_FIR_COEF_HV(1, 7));
+
+ SR(VID_V3_WB_FIR_COEF_V(1, 0));
+ SR(VID_V3_WB_FIR_COEF_V(1, 1));
+ SR(VID_V3_WB_FIR_COEF_V(1, 2));
+ SR(VID_V3_WB_FIR_COEF_V(1, 3));
+ SR(VID_V3_WB_FIR_COEF_V(1, 4));
+ SR(VID_V3_WB_FIR_COEF_V(1, 5));
+ SR(VID_V3_WB_FIR_COEF_V(1, 6));
+ SR(VID_V3_WB_FIR_COEF_V(1, 7));
+
+ SR(VID_V3_WB_ATTRIBUTES(1));
+ SR(VID_V3_WB_CONV_COEF(1, 0));
+ SR(VID_V3_WB_CONV_COEF(1, 1));
+ SR(VID_V3_WB_CONV_COEF(1, 2));
+ SR(VID_V3_WB_CONV_COEF(1, 3));
+ SR(VID_V3_WB_CONV_COEF(1, 4));
+ SR(VID_V3_WB_CONV_COEF(1, 5));
+ SR(VID_V3_WB_CONV_COEF(1, 6));
+ SR(VID_V3_WB_CONV_COEF(1, 7));
+
+ SR(VID_V3_WB_BUF_SIZE_STATUS(1));
+ SR(VID_V3_WB_BUF_THRESHOLD(1));
+ SR(VID_V3_WB_FIR(1));
+ SR(VID_V3_WB_PICTURE_SIZE(1));
+ SR(VID_V3_WB_PIXEL_INC(1));
+ SR(VID_VID3_POSITION);
+ SR(VID_VID3_PRELOAD);
+
+ SR(VID_V3_WB_ROW_INC(1));
+ SR(VID_V3_WB_SIZE(1));
+ SR(VID_V3_WB_FIR2(1));
+ SR(VID_V3_WB_ACCU2_0(1));
+ SR(VID_V3_WB_ACCU2_1(1));
+
+ SR(VID_V3_WB_FIR_COEF_H2(1, 0));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 1));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 2));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 3));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 4));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 5));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 6));
+ SR(VID_V3_WB_FIR_COEF_H2(1, 7));
+
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 0));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 1));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 2));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 3));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 4));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 5));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 6));
+ SR(VID_V3_WB_FIR_COEF_HV2(1, 7));
+
+ SR(VID_V3_WB_FIR_COEF_V2(1, 0));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 1));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 2));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 3));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 4));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 5));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 6));
+ SR(VID_V3_WB_FIR_COEF_V2(1, 7));
+
+ SR(VID_BA_UV0(0));
+ SR(VID_BA_UV0(1));
+
+ SR(VID_BA_UV1(0));
+ SR(VID_BA_UV1(1));
+
+ SR(VID_ATTRIBUTES2(0));
+ SR(VID_ATTRIBUTES2(1));
+ SR(VID_ATTRIBUTES2(2));
+ SR(VID_ATTRIBUTES2(3));
+
+ SR(GAMMA_TABLE(0));
+ SR(GAMMA_TABLE(1));
+ SR(GAMMA_TABLE(2));
+ SR(GAMMA_TABLE(3));
+
+ }
+
/* VID1 */
SR(VID_BA0(0));
SR(VID_BA1(0));
@@ -351,6 +702,214 @@ void dispc_restore_context(void)
RR(SIZE_DIG);
RR(SIZE_LCD);
+ if (cpu_is_omap44xx()) {
+ RR(DIVISOR1);
+ RR(GLOBAL_BUFFER);
+ RR(CONTROL2);
+ RR(DEFAULT_COLOR2);
+ RR(TRANS_COLOR2);
+ RR(CPR2_COEF_B);
+ RR(CPR2_COEF_G);
+ RR(CPR2_COEF_R);
+ RR(DATA2_CYCLE1);
+ RR(DATA2_CYCLE2);
+ RR(DATA2_CYCLE3);
+ RR(SIZE_LCD2);
+ RR(TIMING_H2);
+ RR(TIMING_V2);
+ RR(POL_FREQ2);
+ RR(DIVISOR2);
+
+ RR(CONFIG2);
+
+ /**** VID3 ****/;
+
+ RR(VID_V3_WB_ACCU0(0));
+ RR(VID_V3_WB_ACCU1(0));
+ RR(VID_V3_WB_BA0(0));
+ RR(VID_V3_WB_BA1(0));
+
+ RR(VID_V3_WB_FIR_COEF_H(0, 0));
+ RR(VID_V3_WB_FIR_COEF_H(0, 1));
+ RR(VID_V3_WB_FIR_COEF_H(0, 2));
+ RR(VID_V3_WB_FIR_COEF_H(0, 3));
+ RR(VID_V3_WB_FIR_COEF_H(0, 4));
+ RR(VID_V3_WB_FIR_COEF_H(0, 5));
+ RR(VID_V3_WB_FIR_COEF_H(0, 6));
+ RR(VID_V3_WB_FIR_COEF_H(0, 7));
+
+ RR(VID_V3_WB_FIR_COEF_HV(0, 0));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 1));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 2));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 3));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 4));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 5));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 6));
+ RR(VID_V3_WB_FIR_COEF_HV(0, 7));
+
+ RR(VID_V3_WB_FIR_COEF_V(0, 0));
+ RR(VID_V3_WB_FIR_COEF_V(0, 1));
+ RR(VID_V3_WB_FIR_COEF_V(0, 2));
+ RR(VID_V3_WB_FIR_COEF_V(0, 3));
+ RR(VID_V3_WB_FIR_COEF_V(0, 4));
+ RR(VID_V3_WB_FIR_COEF_V(0, 5));
+ RR(VID_V3_WB_FIR_COEF_V(0, 6));
+ RR(VID_V3_WB_FIR_COEF_V(0, 7));
+
+ RR(VID_V3_WB_ATTRIBUTES(0));
+ RR(VID_V3_WB_CONV_COEF(0, 0));
+ RR(VID_V3_WB_CONV_COEF(0, 1));
+ RR(VID_V3_WB_CONV_COEF(0, 2));
+ RR(VID_V3_WB_CONV_COEF(0, 3));
+ RR(VID_V3_WB_CONV_COEF(0, 4));
+ RR(VID_V3_WB_CONV_COEF(0, 5));
+ RR(VID_V3_WB_CONV_COEF(0, 6));
+ RR(VID_V3_WB_CONV_COEF(0, 7));
+
+ RR(VID_V3_WB_BUF_SIZE_STATUS(0));
+ RR(VID_V3_WB_BUF_THRESHOLD(0));
+ RR(VID_V3_WB_FIR(0));
+ RR(VID_V3_WB_PICTURE_SIZE(0));
+ RR(VID_V3_WB_PIXEL_INC(0));
+ RR(VID_VID3_POSITION);
+ RR(VID_VID3_PRELOAD);
+
+ RR(VID_V3_WB_ROW_INC(0));
+ RR(VID_V3_WB_SIZE(0));
+ RR(VID_V3_WB_FIR2(0));
+ RR(VID_V3_WB_ACCU2_0(0));
+ RR(VID_V3_WB_ACCU2_1(0));
+
+ RR(VID_V3_WB_FIR_COEF_H2(0, 0));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 1));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 2));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 3));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 4));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 5));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 6));
+ RR(VID_V3_WB_FIR_COEF_H2(0, 7));
+
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 0));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 1));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 2));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 3));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 4));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 5));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 6));
+ RR(VID_V3_WB_FIR_COEF_HV2(0, 7));
+
+ RR(VID_V3_WB_FIR_COEF_V2(0, 0));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 1));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 2));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 3));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 4));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 5));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 6));
+ RR(VID_V3_WB_FIR_COEF_V2(0, 7));
+
+ /******* WB Registers *********/;
+
+ RR(VID_V3_WB_ACCU0(1));
+ RR(VID_V3_WB_ACCU1(1));
+ RR(VID_V3_WB_BA0(1));
+ RR(VID_V3_WB_BA1(1));
+
+ RR(VID_V3_WB_FIR_COEF_H(1, 0));
+ RR(VID_V3_WB_FIR_COEF_H(1, 1));
+ RR(VID_V3_WB_FIR_COEF_H(1, 2));
+ RR(VID_V3_WB_FIR_COEF_H(1, 3));
+ RR(VID_V3_WB_FIR_COEF_H(1, 4));
+ RR(VID_V3_WB_FIR_COEF_H(1, 5));
+ RR(VID_V3_WB_FIR_COEF_H(1, 6));
+ RR(VID_V3_WB_FIR_COEF_H(1, 7));
+
+ RR(VID_V3_WB_FIR_COEF_HV(1, 0));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 1));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 2));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 3));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 4));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 5));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 6));
+ RR(VID_V3_WB_FIR_COEF_HV(1, 7));
+
+ RR(VID_V3_WB_FIR_COEF_V(1, 0));
+ RR(VID_V3_WB_FIR_COEF_V(1, 1));
+ RR(VID_V3_WB_FIR_COEF_V(1, 2));
+ RR(VID_V3_WB_FIR_COEF_V(1, 3));
+ RR(VID_V3_WB_FIR_COEF_V(1, 4));
+ RR(VID_V3_WB_FIR_COEF_V(1, 5));
+ RR(VID_V3_WB_FIR_COEF_V(1, 6));
+ RR(VID_V3_WB_FIR_COEF_V(1, 7));
+
+ RR(VID_V3_WB_ATTRIBUTES(1));
+ RR(VID_V3_WB_CONV_COEF(1, 0));
+ RR(VID_V3_WB_CONV_COEF(1, 1));
+ RR(VID_V3_WB_CONV_COEF(1, 2));
+ RR(VID_V3_WB_CONV_COEF(1, 3));
+ RR(VID_V3_WB_CONV_COEF(1, 4));
+ RR(VID_V3_WB_CONV_COEF(1, 5));
+ RR(VID_V3_WB_CONV_COEF(1, 6));
+ RR(VID_V3_WB_CONV_COEF(1, 7));
+
+ RR(VID_V3_WB_BUF_SIZE_STATUS(1));
+ RR(VID_V3_WB_BUF_THRESHOLD(1));
+ RR(VID_V3_WB_FIR(1));
+ RR(VID_V3_WB_PICTURE_SIZE(1));
+ RR(VID_V3_WB_PIXEL_INC(1));
+ RR(VID_VID3_POSITION);
+ RR(VID_VID3_PRELOAD);
+
+ RR(VID_V3_WB_ROW_INC(1));
+ RR(VID_V3_WB_SIZE(1));
+ RR(VID_V3_WB_FIR2(1));
+ RR(VID_V3_WB_ACCU2_0(1));
+ RR(VID_V3_WB_ACCU2_1(1));
+
+ RR(VID_V3_WB_FIR_COEF_H2(1, 0));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 1));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 2));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 3));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 4));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 5));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 6));
+ RR(VID_V3_WB_FIR_COEF_H2(1, 7));
+
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 0));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 1));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 2));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 3));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 4));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 5));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 6));
+ RR(VID_V3_WB_FIR_COEF_HV2(1, 7));
+
+ RR(VID_V3_WB_FIR_COEF_V2(1, 0));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 1));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 2));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 3));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 4));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 5));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 6));
+ RR(VID_V3_WB_FIR_COEF_V2(1, 7));
+
+ RR(VID_BA_UV0(0));
+ RR(VID_BA_UV0(1));
+
+ RR(VID_BA_UV1(0));
+ RR(VID_BA_UV1(1));
+
+ RR(VID_ATTRIBUTES2(0));
+ RR(VID_ATTRIBUTES2(1));
+ RR(VID_ATTRIBUTES2(2));
+ RR(VID_ATTRIBUTES2(3));
+
+ RR(GAMMA_TABLE(0));
+ RR(GAMMA_TABLE(1));
+ RR(GAMMA_TABLE(2));
+ RR(GAMMA_TABLE(3));
+
+ }
+
RR(GFX_BA0);
RR(GFX_BA1);
RR(GFX_POSITION);
@@ -489,219 +1048,168 @@ bool dispc_go_busy(enum omap_channel channel)
{
int bit;
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if ((!cpu_is_omap44xx()) && (channel == OMAP_DSS_CHANNEL_LCD))
+ bit = 5; /* GOLCD */
+ else if (cpu_is_omap44xx() && (channel != OMAP_DSS_CHANNEL_DIGIT))
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
- return REG_GET(DISPC_CONTROL, bit, bit) == 1;
+ if (cpu_is_omap44xx() && (channel == OMAP_DSS_CHANNEL_LCD2))
+ return REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+ else
+ return REG_GET(DISPC_CONTROL, bit, bit) == 1;
+
}
+
void dispc_go(enum omap_channel channel)
{
int bit;
enable_clocks(1);
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if ((channel == OMAP_DSS_CHANNEL_LCD) ||
+ (channel == OMAP_DSS_CHANNEL_LCD2))
bit = 0; /* LCDENABLE */
else
bit = 1; /* DIGITALENABLE */
/* if the channel is not enabled, we don't need GO */
- if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
- goto end;
+ if (cpu_is_omap44xx() && (channel == OMAP_DSS_CHANNEL_LCD2)) {
+ if (REG_GET(DISPC_CONTROL2, bit, bit) == 0)
+ goto end;
+ } else {
+ if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
+ goto end;
+ }
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if ((channel == OMAP_DSS_CHANNEL_LCD) ||
+ (channel == OMAP_DSS_CHANNEL_LCD2))
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
- if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
- DSSERR("GO bit not down for channel %d\n", channel);
- goto end;
+ if (cpu_is_omap44xx() && (channel == OMAP_DSS_CHANNEL_LCD2)) {
+ if (REG_GET(DISPC_CONTROL2, bit, bit) == 1) {
+ /* FIXME PICO DLP on Channel 2 needs GO bit to be UP
+ it will come as error so changing to DSSDBG*/
+ DSSDBG("GO bit not down for channel %d\n", channel);
+ goto end;
+ }
+ } else {
+ if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
+ DSSERR("GO bit not down for channel %d\n", channel);
+ goto end;
+ }
}
- DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
+ DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
+ channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT");
+
+ if (cpu_is_omap44xx() && (channel == OMAP_DSS_CHANNEL_LCD2))
+ REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
- REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
end:
enable_clocks(0);
}
+
+
static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
{
BUG_ON(plane == OMAP_DSS_GFX);
- dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_H(0, reg), value);
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_H(1, reg), value);
}
static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
{
BUG_ON(plane == OMAP_DSS_GFX);
- dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_HV(0, reg), value);
+
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_HV(1, reg), value);
}
static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
{
BUG_ON(plane == OMAP_DSS_GFX);
- dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_V(0, reg), value);
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_V(1, reg), value);
}
-static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
- int vscaleup, int five_taps)
+static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
{
- /* Coefficients for horizontal up-sampling */
- static const u32 coef_hup[8] = {
- 0x00800000,
- 0x0D7CF800,
- 0x1E70F5FF,
- 0x335FF5FE,
- 0xF74949F7,
- 0xF55F33FB,
- 0xF5701EFE,
- 0xF87C0DFF,
- };
-
- /* Coefficients for horizontal down-sampling */
- static const u32 coef_hdown[8] = {
- 0x24382400,
- 0x28371FFE,
- 0x2C361BFB,
- 0x303516F9,
- 0x11343311,
- 0x1635300C,
- 0x1B362C08,
- 0x1F372804,
- };
+ BUG_ON(plane == OMAP_DSS_GFX);
- /* Coefficients for horizontal and vertical up-sampling */
- static const u32 coef_hvup[2][8] = {
- {
- 0x00800000,
- 0x037B02FF,
- 0x0C6F05FE,
- 0x205907FB,
- 0x00404000,
- 0x075920FE,
- 0x056F0CFF,
- 0x027B0300,
- },
- {
- 0x00800000,
- 0x0D7CF8FF,
- 0x1E70F5FE,
- 0x335FF5FB,
- 0xF7404000,
- 0xF55F33FE,
- 0xF5701EFF,
- 0xF87C0D00,
- },
- };
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_H2(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_H2(0, reg), value);
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_H2(1, reg), value);
+}
- /* Coefficients for horizontal and vertical down-sampling */
- static const u32 coef_hvdown[2][8] = {
- {
- 0x24382400,
- 0x28391F04,
- 0x2D381B08,
- 0x3237170C,
- 0x123737F7,
- 0x173732F9,
- 0x1B382DFB,
- 0x1F3928FE,
- },
- {
- 0x24382400,
- 0x28371F04,
- 0x2C361B08,
- 0x3035160C,
- 0x113433F7,
- 0x163530F9,
- 0x1B362CFB,
- 0x1F3728FE,
- },
- };
+static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
- /* Coefficients for vertical up-sampling */
- static const u32 coef_vup[8] = {
- 0x00000000,
- 0x0000FF00,
- 0x0000FEFF,
- 0x0000FBFE,
- 0x000000F7,
- 0x0000FEFB,
- 0x0000FFFE,
- 0x000000FF,
- };
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_HV2(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_HV2(0, reg), value);
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_HV2(1, reg), value);
+}
+static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
- /* Coefficients for vertical down-sampling */
- static const u32 coef_vdown[8] = {
- 0x00000000,
- 0x000004FE,
- 0x000008FB,
- 0x00000CF9,
- 0x0000F711,
- 0x0000F90C,
- 0x0000FB08,
- 0x0000FE04,
- };
+ if ((OMAP_DSS_VIDEO1 == plane) || (OMAP_DSS_VIDEO2 == plane))
+ dispc_write_reg(DISPC_VID_FIR_COEF_V2(plane-1, reg), value);
+ else if (OMAP_DSS_VIDEO3 == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_V2(0, reg), value);
+ else if (OMAP_DSS_WB == plane)
+ dispc_write_reg(DISPC_VID_V3_WB_FIR_COEF_V2(1, reg), value);
+}
- const u32 *h_coef;
- const u32 *hv_coef;
- const u32 *hv_coef_mod;
- const u32 *v_coef;
+static void _dispc_set_scale_coef(enum omap_plane plane, const s8 *hfir,
+ const s8 *vfir, int three_taps)
+{
int i;
-
- if (hscaleup)
- h_coef = coef_hup;
- else
- h_coef = coef_hdown;
-
- if (vscaleup) {
- hv_coef = coef_hvup[five_taps];
- v_coef = coef_vup;
-
- if (hscaleup)
- hv_coef_mod = NULL;
- else
- hv_coef_mod = coef_hvdown[five_taps];
- } else {
- hv_coef = coef_hvdown[five_taps];
- v_coef = coef_vdown;
-
- if (hscaleup)
- hv_coef_mod = coef_hvup[five_taps];
- else
- hv_coef_mod = NULL;
- }
-
- for (i = 0; i < 8; i++) {
- u32 h, hv;
-
- h = h_coef[i];
-
- hv = hv_coef[i];
-
- if (hv_coef_mod) {
- hv &= 0xffffff00;
- hv |= (hv_coef_mod[i] & 0xff);
- }
+ for (i = 0; i < 8; i++, hfir++, vfir++) {
+ u32 h, hv, v;
+ h = ((hfir[0] & 0xFF) | ((hfir[8] << 8) & 0xFF00) |
+ ((hfir[16] << 16) & 0xFF0000) |
+ ((hfir[24] << 24) & 0xFF000000));
+ hv = ((hfir[32] & 0xFF) | ((vfir[8] << 8) & 0xFF00) |
+ ((vfir[16] << 16) & 0xFF0000) |
+ ((vfir[24] << 24) & 0xFF000000));
+ v = ((vfir[0] & 0xFF) | ((vfir[32] << 8) & 0xFF00));
_dispc_write_firh_reg(plane, i, h);
_dispc_write_firhv_reg(plane, i, hv);
- }
-
- if (!five_taps)
- return;
-
- for (i = 0; i < 8; i++) {
- u32 v;
- v = v_coef[i];
_dispc_write_firv_reg(plane, i, v);
+ if (three_taps && v)
+ printk(KERN_ERR "three_tap v is %x\n", v);
}
}
@@ -731,6 +1239,33 @@ static void _dispc_setup_color_conv_coef(void)
dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
+ if (cpu_is_omap44xx()) {
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(0, 0),
+ CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(0, 1),
+ CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(0, 2),
+ CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(0, 3),
+ CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(0, 4),
+ CVAL(0, ct->bcb));
+ REG_FLD_MOD(DISPC_VID_V3_WB_ATTRIBUTES(0), ct->full_range, 11, 11);
+ /* Writeback */
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(1, 0),
+ CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(1, 1),
+ CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(1, 2),
+ CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(1, 3),
+ CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_VID_V3_WB_CONV_COEF(1, 4),
+ CVAL(0, ct->bcb));
+
+ REG_FLD_MOD(DISPC_VID_V3_WB_ATTRIBUTES(1), ct->full_range, 11, 11);
+
+ }
#undef CVAL
@@ -741,46 +1276,93 @@ static void _dispc_setup_color_conv_coef(void)
static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
{
- const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
+ struct dispc_reg ba0_reg[5] = { DISPC_GFX_BA0,
DISPC_VID_BA0(0),
DISPC_VID_BA0(1) };
+ if (cpu_is_omap44xx()) {
+ ba0_reg[3] = DISPC_VID_V3_WB_BA0(0); /* VID 3 pipeline*/
+ ba0_reg[4] = DISPC_VID_V3_WB_BA0(1); /* WB pipeline*/
+ }
dispc_write_reg(ba0_reg[plane], paddr);
}
static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
{
- const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
+ struct dispc_reg ba1_reg[5] = { DISPC_GFX_BA1,
DISPC_VID_BA1(0),
DISPC_VID_BA1(1) };
+ if (cpu_is_omap44xx()) {
+ ba1_reg[3] = DISPC_VID_V3_WB_BA1(0); /* VID 3 pipeline*/
+ ba1_reg[4] = DISPC_VID_V3_WB_BA1(1); /* WB pipeline*/
+ }
dispc_write_reg(ba1_reg[plane], paddr);
}
+static void _dispc_set_plane_ba_uv0(enum omap_plane plane, u32 paddr)
+{
+ const struct dispc_reg ba_uv0_reg[] = { DISPC_VID_BA_UV0(0),
+ DISPC_VID_BA_UV0(1),
+ DISPC_VID_BA_UV0(2), /* VID 3 pipeline*/
+ DISPC_VID_BA_UV0(3), /* WB pipeline*/
+ };
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_write_reg(ba_uv0_reg[plane - 1], paddr);
+ /* plane - 1 => no UV_BA for GFX*/
+
+}
+
+static void _dispc_set_plane_ba_uv1(enum omap_plane plane, u32 paddr)
+{
+ const struct dispc_reg ba_uv1_reg[] = { DISPC_VID_BA_UV1(0),
+ DISPC_VID_BA_UV1(1),
+ DISPC_VID_BA_UV1(2)
+ };
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_write_reg(ba_uv1_reg[plane - 1], paddr);
+ /* plane - 1 => no UV_BA for GFX*/
+}
+
+
static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
{
- const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
+ struct dispc_reg pos_reg[4] = { DISPC_GFX_POSITION,
DISPC_VID_POSITION(0),
DISPC_VID_POSITION(1) };
-
u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
+ if (cpu_is_omap44xx())
+ pos_reg[3] = DISPC_VID_VID3_POSITION; /* VID 3 pipeline*/
+
dispc_write_reg(pos_reg[plane], val);
}
static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
{
- const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
+ struct dispc_reg siz_reg[5] = { DISPC_GFX_SIZE,
DISPC_VID_PICTURE_SIZE(0),
DISPC_VID_PICTURE_SIZE(1) };
u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
+ if (cpu_is_omap44xx()) {
+ siz_reg[3] = DISPC_VID_V3_WB_PICTURE_SIZE(0); /* VID3 pipeline*/
+ siz_reg[4] = DISPC_VID_V3_WB_PICTURE_SIZE(1); /* WB pipeline*/
+ }
dispc_write_reg(siz_reg[plane], val);
}
static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
{
u32 val;
- const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
+ struct dispc_reg vsi_reg[4] = { DISPC_VID_SIZE(0),
DISPC_VID_SIZE(1) };
+ if (cpu_is_omap44xx()) {
+ vsi_reg[2] = DISPC_VID_V3_WB_SIZE(0); /* VID 3 pipeline*/
+ vsi_reg[3] = DISPC_VID_V3_WB_SIZE(1); /* WB pipeline*/
+ }
BUG_ON(plane == OMAP_DSS_GFX);
@@ -790,8 +1372,8 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
{
-
- BUG_ON(plane == OMAP_DSS_VIDEO1);
+ if (!cpu_is_omap44xx())
+ BUG_ON(plane == OMAP_DSS_VIDEO1);
if (cpu_is_omap24xx())
return;
@@ -800,22 +1382,34 @@ static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
else if (plane == OMAP_DSS_VIDEO2)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
+ else if (plane == OMAP_DSS_VIDEO1)
+ REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 15, 8);
+ else if (plane == OMAP_DSS_VIDEO3)
+ REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 31, 24);
+
}
static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
{
- const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
+ struct dispc_reg ri_reg[5] = { DISPC_GFX_PIXEL_INC,
DISPC_VID_PIXEL_INC(0),
DISPC_VID_PIXEL_INC(1) };
-
+ if (cpu_is_omap44xx()) {
+ ri_reg[3] = DISPC_VID_V3_WB_PIXEL_INC(0);
+ ri_reg[4] = DISPC_VID_V3_WB_PIXEL_INC(1); /* WB pipeline*/
+ }
dispc_write_reg(ri_reg[plane], inc);
}
static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
{
- const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
+ struct dispc_reg ri_reg[5] = { DISPC_GFX_ROW_INC,
DISPC_VID_ROW_INC(0),
- DISPC_VID_ROW_INC(1) };
+ DISPC_VID_ROW_INC(1)};
+ if (cpu_is_omap44xx()) {
+ ri_reg[3] = DISPC_VID_V3_WB_ROW_INC(0);
+ ri_reg[4] = DISPC_VID_V3_WB_ROW_INC(1); /* WB pipeline*/
+ }
dispc_write_reg(ri_reg[plane], inc);
}
@@ -824,38 +1418,74 @@ static void _dispc_set_color_mode(enum omap_plane plane,
enum omap_color_mode color_mode)
{
u32 m = 0;
-
- switch (color_mode) {
- case OMAP_DSS_COLOR_CLUT1:
- m = 0x0; break;
- case OMAP_DSS_COLOR_CLUT2:
- m = 0x1; break;
- case OMAP_DSS_COLOR_CLUT4:
- m = 0x2; break;
- case OMAP_DSS_COLOR_CLUT8:
- m = 0x3; break;
- case OMAP_DSS_COLOR_RGB12U:
- m = 0x4; break;
- case OMAP_DSS_COLOR_ARGB16:
- m = 0x5; break;
- case OMAP_DSS_COLOR_RGB16:
- m = 0x6; break;
- case OMAP_DSS_COLOR_RGB24U:
- m = 0x8; break;
- case OMAP_DSS_COLOR_RGB24P:
- m = 0x9; break;
- case OMAP_DSS_COLOR_YUV2:
- m = 0xa; break;
- case OMAP_DSS_COLOR_UYVY:
- m = 0xb; break;
- case OMAP_DSS_COLOR_ARGB32:
- m = 0xc; break;
- case OMAP_DSS_COLOR_RGBA32:
- m = 0xd; break;
- case OMAP_DSS_COLOR_RGBX32:
- m = 0xe; break;
- default:
- BUG(); break;
+ if ((!cpu_is_omap44xx()) || (OMAP_DSS_GFX == plane)) {
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ m = 0x0; break;
+ case OMAP_DSS_COLOR_CLUT2:
+ m = 0x1; break;
+ case OMAP_DSS_COLOR_CLUT4:
+ m = 0x2; break;
+ case OMAP_DSS_COLOR_CLUT8:
+ m = 0x3; break;
+ case OMAP_DSS_COLOR_RGB12U:
+ m = 0x4; break;
+ case OMAP_DSS_COLOR_ARGB16:
+ m = 0x5; break;
+ case OMAP_DSS_COLOR_RGB16:
+ m = 0x6; break;
+ case OMAP_DSS_COLOR_RGB24U:
+ m = 0x8; break;
+ case OMAP_DSS_COLOR_RGB24P:
+ m = 0x9; break;
+ case OMAP_DSS_COLOR_YUV2:
+ m = 0xa; break;
+ case OMAP_DSS_COLOR_UYVY:
+ m = 0xb; break;
+ case OMAP_DSS_COLOR_ARGB32:
+ m = 0xc; break;
+ case OMAP_DSS_COLOR_RGBA32:
+ m = 0xd; break;
+ case OMAP_DSS_COLOR_RGBX32:
+ m = 0xe; break;
+ default:
+ BUG(); break;
+ }
+ } else {
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ m = 0x0; break;
+ case OMAP_DSS_COLOR_RGB12U:
+ m = 0x1; break;
+ case OMAP_DSS_COLOR_RGBA12:
+ m = 0x2; break;
+ case OMAP_DSS_COLOR_XRGB12:
+ m = 0x4; break;
+ case OMAP_DSS_COLOR_ARGB16:
+ m = 0x5; break;
+ case OMAP_DSS_COLOR_RGB16:
+ m = 0x6; break;
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ m = 0x7; break;
+ case OMAP_DSS_COLOR_RGB24U:
+ m = 0x8; break;
+ case OMAP_DSS_COLOR_RGB24P:
+ m = 0x9; break;
+ case OMAP_DSS_COLOR_YUV2:
+ m = 0xA; break;
+ case OMAP_DSS_COLOR_UYVY:
+ m = 0xB; break;
+ case OMAP_DSS_COLOR_ARGB32:
+ m = 0xC; break;
+ case OMAP_DSS_COLOR_RGBA32:
+ m = 0xD; break;
+ case OMAP_DSS_COLOR_RGBX24_32_ALGN:
+ m = 0xE; break;
+ case OMAP_DSS_COLOR_XRGB15:
+ m = 0xF; break;
+ default:
+ BUG(); break;
+ }
}
REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
@@ -866,6 +1496,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
{
int shift;
u32 val;
+ int chan = 0, chan2 = 0;
switch (plane) {
case OMAP_DSS_GFX:
@@ -873,6 +1504,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
break;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
shift = 16;
break;
default:
@@ -881,7 +1513,30 @@ static void _dispc_set_channel_out(enum omap_plane plane,
}
val = dispc_read_reg(dispc_reg_att[plane]);
- val = FLD_MOD(val, channel, shift, shift);
+ if (cpu_is_omap44xx()) {
+ switch (channel) {
+
+ case OMAP_DSS_CHANNEL_LCD:
+ chan = 0;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ chan = 1;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ chan = 0;
+ chan2 = 1;
+ break;
+ default:
+ BUG();
+ }
+
+ val = FLD_MOD(val, chan, shift, shift);
+ val = FLD_MOD(val, chan2, 31, 30);
+ } else {
+ val = FLD_MOD(val, channel, shift, shift);
+ }
dispc_write_reg(dispc_reg_att[plane], val);
}
@@ -899,6 +1554,8 @@ void dispc_set_burst_size(enum omap_plane plane,
break;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB: /* WB pipeline */
shift = 14;
break;
default:
@@ -913,6 +1570,48 @@ void dispc_set_burst_size(enum omap_plane plane,
enable_clocks(0);
}
+void dispc_set_zorder(enum omap_plane plane,
+ enum omap_overlay_zorder zorder)
+{
+ u32 val;
+
+ BUG_ON(plane == OMAP_DSS_WB);
+ val = dispc_read_reg(dispc_reg_att[plane]);
+ val = FLD_MOD(val, zorder, 27, 26);
+ dispc_write_reg(dispc_reg_att[plane], val);
+
+}
+
+void dispc_enable_zorder(enum omap_plane plane, bool enable)
+{
+ u32 val;
+
+ BUG_ON(plane == OMAP_DSS_WB);
+ val = dispc_read_reg(dispc_reg_att[plane]);
+ val = FLD_MOD(val, enable, 25, 25);
+ dispc_write_reg(dispc_reg_att[plane], val);
+
+}
+
+
+void dispc_set_idle_mode(void)
+{
+ u32 l;
+
+ l = dispc_read_reg(DISPC_SYSCONFIG);
+ l = FLD_MOD(l, 1, 13, 12); /* MIDLEMODE: smart standby */
+ l = FLD_MOD(l, 1, 4, 3); /* SIDLEMODE: smart idle */
+ l = FLD_MOD(l, 0, 2, 2); /* ENWAKEUP */
+ l = FLD_MOD(l, 0, 0, 0); /* AUTOIDLE */
+ dispc_write_reg(DISPC_SYSCONFIG, l);
+
+}
+
+void dispc_enable_gamma_table(bool enable)
+{
+ REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
+}
+
static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
{
u32 val;
@@ -927,6 +1626,7 @@ static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
void dispc_enable_replication(enum omap_plane plane, bool enable)
{
int bit;
+ BUG_ON(plane == OMAP_DSS_WB);
if (plane == OMAP_DSS_GFX)
bit = 5;
@@ -938,13 +1638,16 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
enable_clocks(0);
}
-void dispc_set_lcd_size(u16 width, u16 height)
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
{
u32 val;
BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
enable_clocks(1);
- dispc_write_reg(DISPC_SIZE_LCD, val);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ dispc_write_reg(DISPC_SIZE_LCD2, val);
+ else
+ dispc_write_reg(DISPC_SIZE_LCD, val);
enable_clocks(0);
}
@@ -960,11 +1663,15 @@ void dispc_set_digit_size(u16 width, u16 height)
static void dispc_read_plane_fifo_sizes(void)
{
- const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
+ struct dispc_reg fsz_reg[5] = { DISPC_GFX_FIFO_SIZE_STATUS,
DISPC_VID_FIFO_SIZE_STATUS(0),
DISPC_VID_FIFO_SIZE_STATUS(1) };
u32 size;
int plane;
+ if (cpu_is_omap44xx()) {
+ fsz_reg[3] = DISPC_VID_V3_WB_BUF_SIZE_STATUS(0);
+ fsz_reg[4] = DISPC_VID_V3_WB_BUF_SIZE_STATUS(1); /* WB pipeline*/
+ }
enable_clocks(1);
@@ -973,6 +1680,8 @@ static void dispc_read_plane_fifo_sizes(void)
size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
else if (cpu_is_omap34xx())
size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
+ else if (cpu_is_omap44xx())
+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 15, 0);
else
BUG();
@@ -989,9 +1698,13 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
{
- const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
+ struct dispc_reg ftrs_reg[5] = { DISPC_GFX_FIFO_THRESHOLD,
DISPC_VID_FIFO_THRESHOLD(0),
DISPC_VID_FIFO_THRESHOLD(1) };
+ if (cpu_is_omap44xx()) {
+ ftrs_reg[3] = DISPC_VID_V3_WB_BUF_THRESHOLD(0);
+ ftrs_reg[4] = DISPC_VID_V3_WB_BUF_THRESHOLD(1);
+ }
enable_clocks(1);
DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
@@ -1003,9 +1716,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
if (cpu_is_omap24xx())
dispc_write_reg(ftrs_reg[plane],
FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
- else
+ else if (cpu_is_omap34xx())
+ dispc_write_reg(ftrs_reg[plane],
+ FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
+ else /* cpu is omap44xx */
dispc_write_reg(ftrs_reg[plane],
- FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
+ FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
enable_clocks(0);
}
@@ -1023,9 +1739,12 @@ void dispc_enable_fifomerge(bool enable)
static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
{
u32 val;
- const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
+ struct dispc_reg fir_reg[4] = { DISPC_VID_FIR(0),
DISPC_VID_FIR(1) };
-
+ if (cpu_is_omap44xx()) {
+ fir_reg[2] = DISPC_VID_V3_WB_FIR(0);
+ fir_reg[3] = DISPC_VID_V3_WB_FIR(1); /* WB pipeline*/
+ }
BUG_ON(plane == OMAP_DSS_GFX);
if (cpu_is_omap24xx())
@@ -1038,71 +1757,287 @@ static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
{
u32 val;
- const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
+ struct dispc_reg ac0_reg[4] = { DISPC_VID_ACCU0(0),
DISPC_VID_ACCU0(1) };
+ if (cpu_is_omap44xx()) {
+ ac0_reg[2] = DISPC_VID_V3_WB_ACCU0(0); /* VID 3 pipeline*/
+ ac0_reg[3] = DISPC_VID_V3_WB_ACCU0(1); /* WB pipeline*/
+ }
BUG_ON(plane == OMAP_DSS_GFX);
+ if (cpu_is_omap44xx())
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+ else
+ val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
- val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
dispc_write_reg(ac0_reg[plane-1], val);
}
static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
{
u32 val;
- const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
+ struct dispc_reg ac1_reg[4] = { DISPC_VID_ACCU1(0),
DISPC_VID_ACCU1(1) };
+ if (cpu_is_omap44xx()) {
+ ac1_reg[2] = DISPC_VID_V3_WB_ACCU1(0); /* VID 3 pipeline*/
+ ac1_reg[3] = DISPC_VID_V3_WB_ACCU1(1); /* WB pipeline*/
+ }
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+ if (cpu_is_omap44xx())
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+ else
+ val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+ dispc_write_reg(ac1_reg[plane-1], val);
+}
+
+static void _dispc_set_fir2(enum omap_plane plane, int hinc, int vinc)
+{
+ u32 val;
+ const struct dispc_reg fir_reg[] = { DISPC_VID_FIR2(0),
+ DISPC_VID_FIR2(1),
+ DISPC_VID_V3_WB_FIR2(0),
+ /* VID 3 pipeline*/
+ DISPC_VID_V3_WB_FIR2(1)
+ /* WB pipeline*/
+
+ };
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+
+ dispc_write_reg(fir_reg[plane-1], val);
+}
+
+static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
+{
+ u32 val;
+ const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU2_0(0),
+ DISPC_VID_ACCU2_0(1),
+ DISPC_VID_V3_WB_ACCU2_0(0),
+ DISPC_VID_V3_WB_ACCU2_0(1) /* WB */
+ };
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+ dispc_write_reg(ac0_reg[plane-1], val);
+}
+
+static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
+{
+ u32 val;
+ const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU2_1(0),
+ DISPC_VID_ACCU2_1(1),
+ DISPC_VID_V3_WB_ACCU2_1(0),
+ DISPC_VID_V3_WB_ACCU2_1(1)
+ };
BUG_ON(plane == OMAP_DSS_GFX);
- val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
dispc_write_reg(ac1_reg[plane-1], val);
}
+static const s8 fir5_zero[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const s8 fir3_m8[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 5, 7, 64, 32, 12, 3,
+ 128, 123, 111, 89, 64, 89, 111, 123,
+ 0, 3, 12, 32, 0, 7, 5, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const s8 fir5_m8[] = {
+ 17, 18, 15, 9, -18, -6, 5, 13,
+ -20, -27, -30, -27, 81, 47, 17, -4,
+ 134, 127, 121, 105, 81, 105, 121, 127,
+ -20, -4, 17, 47, -18, -27, -30, -27,
+ 17, 14, 5, -6, 2, 9, 15, 19,
+};
+static const s8 fir5_m8b[] = {
+ 0, 0, -1, -2, -9, -5, -2, -1,
+ 0, -8, -11, -11, 73, 51, 30, 13,
+ 128, 124, 112, 95, 73, 95, 112, 124,
+ 0, 13, 30, 51, -9, -11, -11, -8,
+ 0, -1, -2, -5, 0, -2, -1, 0,
+};
+static const s8 fir5_m9[] = {
+ 8, 14, 17, 17, -26, -18, -9, 1,
+ -8, -21, -27, -30, 83, 56, 30, 8,
+ 128, 126, 117, 103, 83, 103, 117, 126,
+ -8, 8, 30, 56, -26, -30, -27, -21,
+ 8, 1, -9, -18, 14, 17, 17, 14,
+};
+static const s8 fir5_m10[] = {
+ -2, 5, 11, 15, -28, -24, -18, -10,
+ 2, -12, -22, -27, 83, 62, 41, 20,
+ 128, 125, 116, 102, 83, 102, 116, 125,
+ 2, 20, 41, 62, -28, -27, -22, -12,
+ -2, -10, -18, -24, 18, 15, 11, 5,
+};
+static const s8 fir5_m11[] = {
+ -12, -4, 3, 9, -26, -27, -24, -19,
+ 12, -3, -15, -22, 83, 67, 49, 30,
+ 128, 124, 115, 101, 83, 101, 115, 124,
+ 12, 30, 49, 67, -26, -22, -15, -3,
+ -12, -19, -24, -27, 14, 9, 3, -4,
+};
+static const s8 fir5_m12[] = {
+ -19, -12, -6, 1, -21, -25, -26, -24,
+ 21, 6, -7, -16, 82, 70, 55, 38,
+ 124, 120, 112, 98, 82, 98, 112, 120,
+ 21, 38, 55, 70, -21, -16, -7, 6,
+ -19, -24, -26, -25, 6, 1, -6, -12,
+};
+static const s8 fir5_m13[] = {
+ -22, -18, -12, -6, -17, -22, -25, -25,
+ 27, 13, 0, -10, 81, 71, 58, 43,
+ 118, 115, 107, 95, 81, 95, 107, 115,
+ 27, 43, 58, 71, -17, -10, 0, 13,
+ -22, -25, -25, -22, 0, -6, -12, -18,
+};
+static const s8 fir5_m14[] = {
+ -23, -20, -16, -11, -11, -18, -22, -24,
+ 32, 18, 6, -4, 78, 70, 59, 46,
+ 110, 108, 101, 91, 78, 91, 101, 108,
+ 32, 46, 59, 70, -11, -4, 6, 18,
+ -23, -24, -22, -18, -6, -11, -16, -20,
+};
+static const s8 fir3_m16[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 36, 31, 27, 23, 55, 50, 45, 40,
+ 56, 57, 56, 55, 55, 55, 56, 57,
+ 36, 40, 45, 50, 18, 23, 27, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const s8 fir5_m16[] = {
+ -20, -21, -19, -17, -2, -9, -14, -18,
+ 37, 26, 15, 6, 73, 66, 58, 48,
+ 94, 93, 88, 82, 73, 82, 88, 93,
+ 37, 48, 58, 66, -2, 6, 15, 26,
+ -20, -18, -14, -9, -14, -17, -19, -21,
+};
+static const s8 fir5_m19[] = {
+ -12, -14, -16, -16, 8, 1, -4, -9,
+ 38, 31, 22, 15, 64, 59, 53, 47,
+ 76, 72, 73, 69, 64, 69, 73, 72,
+ 38, 47, 53, 59, 8, 15, 22, 31,
+ -12, -8, -4, 1, -16, -16, -16, -13,
+};
+static const s8 fir5_m22[] = {
+ -6, -8, -11, -13, 13, 8, 3, -2,
+ 37, 32, 25, 19, 58, 53, 48, 44,
+ 66, 61, 63, 61, 58, 61, 63, 61,
+ 37, 44, 48, 53, 13, 19, 25, 32,
+ -6, -1, 3, 8, -14, -13, -11, -7,
+};
+static const s8 fir5_m26[] = {
+ 1, -2, -5, -8, 18, 13, 8, 4,
+ 36, 31, 27, 22, 51, 48, 44, 40,
+ 54, 55, 54, 53, 51, 53, 54, 55,
+ 36, 40, 44, 48, 18, 22, 27, 31,
+ 1, 4, 8, 13, -10, -8, -5, -2,
+};
+static const s8 fir5_m32[] = {
+ 7, 4, 1, -1, 21, 17, 14, 10,
+ 34, 31, 27, 24, 45, 42, 39, 37,
+ 46, 46, 46, 46, 45, 46, 46, 46,
+ 34, 37, 39, 42, 21, 24, 28, 31,
+ 7, 10, 14, 17, -4, -1, 1, 4,
+};
+
+static const s8 *get_scaling_coef(int orig_size, int out_size,
+ int orig_ilaced, int out_ilaced,
+ int three_tap)
+{
+ /* ranges from 2 to 32 */
+ int two_m = 16 * orig_size / out_size;
+
+ if (orig_size > 4 * out_size)
+ return fir5_zero;
+
+ if (out_size > 8 * orig_size)
+ return three_tap ? fir3_m8 : fir5_m8;
+ /* interlaced output needs at least M = 16 */
+ if (out_ilaced) {
+ if (two_m < 32)
+ two_m = 32;
+ }
+ if (three_tap)
+ return two_m < 24 ? fir3_m8 : fir3_m16;
+
+ return orig_size < out_size ? fir5_m8b :
+ two_m < 17 ? fir5_m8 :
+ two_m < 19 ? fir5_m9 :
+ two_m < 21 ? fir5_m10 :
+ two_m < 23 ? fir5_m11 :
+ two_m < 25 ? fir5_m12 :
+ two_m < 27 ? fir5_m13 :
+ two_m < 30 ? fir5_m14 :
+ two_m < 35 ? fir5_m16 :
+ two_m < 41 ? fir5_m19 :
+ two_m < 48 ? fir5_m22 :
+ two_m < 58 ? fir5_m26 :
+ fir5_m32;
+}
static void _dispc_set_scaling(enum omap_plane plane,
u16 orig_width, u16 orig_height,
u16 out_width, u16 out_height,
- bool ilace, bool five_taps,
- bool fieldmode)
+ bool ilace, bool three_taps,
+ bool fieldmode, int scale_x, int scale_y)
{
int fir_hinc;
int fir_vinc;
- int hscaleup, vscaleup;
int accu0 = 0;
int accu1 = 0;
u32 l;
+ const s8 *hfir, *vfir;
BUG_ON(plane == OMAP_DSS_GFX);
- hscaleup = orig_width <= out_width;
- vscaleup = orig_height <= out_height;
-
- _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
-
- if (!orig_width || orig_width == out_width)
+ if (scale_x) {
+ fir_hinc = 1024 * (orig_width - 1) / (out_width - 1);
+ if (fir_hinc > 4095)
+ fir_hinc = 4095;
+ hfir = get_scaling_coef(orig_width, out_width, 0, 0, 0);
+ } else {
fir_hinc = 0;
- else
- fir_hinc = 1024 * orig_width / out_width;
+ hfir = fir5_zero;
+ }
- if (!orig_height || orig_height == out_height)
+ if (scale_y) {
+ fir_vinc = 1024 * (orig_height - 1) / (out_height - 1);
+ if (fir_vinc > 4095)
+ fir_vinc = 4095;
+ vfir = get_scaling_coef(orig_height, out_height, 0, 0,
+ three_taps);
+ } else {
fir_vinc = 0;
- else
- fir_vinc = 1024 * orig_height / out_height;
+ vfir = fir5_zero;
+ }
+ _dispc_set_scale_coef(plane, hfir, vfir, three_taps);
_dispc_set_fir(plane, fir_hinc, fir_vinc);
l = dispc_read_reg(dispc_reg_att[plane]);
- l &= ~((0x0f << 5) | (0x3 << 21));
-
+ if (!cpu_is_omap44xx()) {
+ l &= ~((0x0f << 5) | (0x3 << 21));
+ l |= out_width > orig_width ? 0 : (1 << 7);
+ l |= out_height > orig_height ? 0 : (1 << 8);
+ } else
+ l &= ~((0x03 << 5) | (0x1 << 21));
l |= fir_hinc ? (1 << 5) : 0;
l |= fir_vinc ? (1 << 6) : 0;
- l |= hscaleup ? 0 : (1 << 7);
- l |= vscaleup ? 0 : (1 << 8);
-
- l |= five_taps ? (1 << 21) : 0;
- l |= five_taps ? (1 << 22) : 0;
+ l |= three_taps ? 0 : (1 << 21);
dispc_write_reg(dispc_reg_att[plane], l);
@@ -1123,54 +2058,140 @@ static void _dispc_set_scaling(enum omap_plane plane,
_dispc_set_vid_accu1(plane, 0, accu1);
}
-static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
- bool mirroring, enum omap_color_mode color_mode)
+static void _dispc_set_scaling_uv(enum omap_plane plane,
+ u16 orig_width, u16 orig_height,
+ u16 out_width, u16 out_height,
+ bool ilace, bool three_taps,
+ bool fieldmode, int scale_x, int scale_y)
{
- if (color_mode == OMAP_DSS_COLOR_YUV2 ||
- color_mode == OMAP_DSS_COLOR_UYVY) {
- int vidrot = 0;
+ int i;
+ int fir_hinc, fir_vinc;
+ int accu0, accu1, accuh;
+ const s8 *hfir, *vfir;
+
+ if (scale_x) {
+ fir_hinc = 1024 * (orig_width - 1) / (out_width - 1);
+ if (fir_hinc > 4095)
+ fir_hinc = 4095;
+ hfir = get_scaling_coef(orig_width, out_width, 0, 0, 0);
+ } else {
+ fir_hinc = 0;
+ hfir = fir5_zero;
+ }
- if (mirroring) {
- switch (rotation) {
- case OMAP_DSS_ROT_0:
- vidrot = 2;
- break;
- case OMAP_DSS_ROT_90:
- vidrot = 1;
- break;
- case OMAP_DSS_ROT_180:
- vidrot = 0;
- break;
- case OMAP_DSS_ROT_270:
- vidrot = 3;
- break;
- }
- } else {
- switch (rotation) {
- case OMAP_DSS_ROT_0:
- vidrot = 0;
- break;
- case OMAP_DSS_ROT_90:
- vidrot = 1;
- break;
- case OMAP_DSS_ROT_180:
- vidrot = 2;
- break;
- case OMAP_DSS_ROT_270:
- vidrot = 3;
- break;
- }
+ if (scale_y) {
+ fir_vinc = 1024 * (orig_height - 0) / (out_height - 0);
+ if (fir_vinc > 4095)
+ fir_vinc = 4095;
+ vfir = get_scaling_coef(orig_height, out_height, 0,
+ ilace, three_taps);
+ } else {
+ fir_vinc = 0;
+ vfir = fir5_zero;
}
- REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+ for (i = 0; i < 8; i++, hfir++, vfir++) {
+ u32 h, hv, v;
+ h = ((hfir[0] & 0xFF) | ((hfir[8] << 8) & 0xFF00) |
+ ((hfir[16] << 16) & 0xFF0000) |
+ ((hfir[24] << 24) & 0xFF000000));
+ hv = ((hfir[32] & 0xFF) | ((vfir[8] << 8) & 0xFF00) |
+ ((vfir[16] << 16) & 0xFF0000) |
+ ((vfir[24] << 24) & 0xFF000000));
+ v = ((vfir[0] & 0xFF) | ((vfir[32] << 8) & 0xFF00));
+
+ _dispc_write_firh2_reg(plane, i, h);
+ _dispc_write_firhv2_reg(plane, i, hv);
+ _dispc_write_firv2_reg(plane, i, v);
+ if (three_taps && v)
+ printk(KERN_ERR "three_tap v is %x\n", v);
+ }
- if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
- REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
- else
- REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
+ /* set chroma resampling */
+ REG_FLD_MOD(DISPC_VID_ATTRIBUTES2(plane - 1),
+ (fir_hinc || fir_vinc) ? 1 : 0, 8, 8);
+
+ /* set H scaling */
+ REG_FLD_MOD(dispc_reg_att[plane], fir_hinc ? 1 : 0, 6, 6);
+
+ /* set V scaling */
+ REG_FLD_MOD(dispc_reg_att[plane], fir_vinc ? 1 : 0, 5, 5);
+
+ _dispc_set_fir2(plane, fir_hinc, fir_vinc);
+
+ if (ilace) {
+ accu0 = (-3 * fir_vinc / 4) % 1024;
+ accu1 = (-fir_vinc / 4) % 1024;
} else {
- REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
- REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
+ accu0 = accu1 = (-fir_vinc / 2) % 1024;
+ }
+ accuh = (-fir_hinc / 2) % 1024;
+
+ _dispc_set_vid_accu2_0(plane, 0x80, 0);
+ _dispc_set_vid_accu2_1(plane, 0x80, 0);
+ /* _dispc_set_vid_accu2_0(plane, accuh, accu0);
+ _dispc_set_vid_accu2_1(plane, accuh, accu1); */
+}
+static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
+ bool mirroring, enum omap_color_mode color_mode)
+{
+ BUG_ON(plane == OMAP_DSS_WB);
+ if (!cpu_is_omap44xx()) {
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY) {
+ int vidrot = 0;
+
+ if (mirroring) {
+ switch (rotation) {
+ case OMAP_DSS_ROT_0:
+ vidrot = 2;
+ break;
+ case OMAP_DSS_ROT_90:
+ vidrot = 1;
+ break;
+ case OMAP_DSS_ROT_180:
+ vidrot = 0;
+ break;
+ case OMAP_DSS_ROT_270:
+ vidrot = 3;
+ break;
+ }
+ } else {
+ switch (rotation) {
+ case OMAP_DSS_ROT_0:
+ vidrot = 0;
+ break;
+ case OMAP_DSS_ROT_90:
+ vidrot = 1;
+ break;
+ case OMAP_DSS_ROT_180:
+ vidrot = 2;
+ break;
+ case OMAP_DSS_ROT_270:
+ vidrot = 3;
+ break;
+ }
+ }
+
+ REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+
+ if (rotation == OMAP_DSS_ROT_90 ||
+ rotation == OMAP_DSS_ROT_270)
+ REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
+ else
+ REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
+ } else {
+ REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
+ REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
+ }
+ } else if (plane != OMAP_DSS_GFX) {
+ if (color_mode == OMAP_DSS_COLOR_NV12) {
+ /* DOUBLESTRIDE : 0 for 90-, 270-; 1 for 0- and 180- */
+ if (rotation == 1 || rotation == 3)
+ REG_FLD_MOD(dispc_reg_att[plane], 0x0, 22, 22);
+ else
+ REG_FLD_MOD(dispc_reg_att[plane], 0x1, 22, 22);
+ }
}
}
@@ -1215,6 +2236,69 @@ static s32 pixinc(int pixels, u8 ps)
BUG();
}
+ static void calc_tiler_row_rotation(u8 rotation,
+ u16 width, u16 height,
+ enum omap_color_mode color_mode,
+ s32 *row_inc)
+ {
+ u8 ps = 1;
+ DSSDBG("calc_tiler_rot(%d): %dx%d\n", rotation, width, height);
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_ARGB16:
+
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ ps = 2;
+ break;
+
+ case OMAP_DSS_COLOR_RGB24P:
+ case OMAP_DSS_COLOR_RGB24U:
+ case OMAP_DSS_COLOR_ARGB32:
+ case OMAP_DSS_COLOR_RGBA32:
+ case OMAP_DSS_COLOR_RGBX32:
+ ps = 4;
+ break;
+
+ case OMAP_DSS_COLOR_NV12:
+ ps = 1;
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+ switch (rotation) {
+ case 0:
+ case 2:
+ if (1 == ps)
+ *row_inc = 16384 + 1 - (width);
+ else
+ *row_inc = 32768 + 1 - (width * ps);
+ break;
+
+ case 1:
+ case 3:
+ if (4 == ps)
+ *row_inc = 16384 + 1 - (width * ps);
+ else
+ *row_inc = 8192 + 1 - (width * ps);
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+
+ DSSDBG(" colormode: %d, rotation: %d, ps: %d, width: %d,"
+ " height: %d, row_inc:%d\n",
+ color_mode, rotation, ps, width, height, *row_inc);
+
+ return;
+ }
+
+
static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
u16 screen_width,
u16 width, u16 height,
@@ -1439,12 +2523,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
}
}
-static unsigned long calc_fclk_five_taps(u16 width, u16 height,
- u16 out_width, u16 out_height, enum omap_color_mode color_mode)
+static unsigned long calc_fclk_five_taps(enum omap_channel channel,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode)
{
u32 fclk = 0;
/* FIXME venc pclk? */
- u64 tmp, pclk = dispc_pclk_rate();
+ u64 tmp, pclk = dispc_pclk_rate(channel);
if (height > out_height) {
/* FIXME get real display PPL */
@@ -1476,8 +2561,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height,
return fclk;
}
-static unsigned long calc_fclk(u16 width, u16 height,
- u16 out_width, u16 out_height)
+static unsigned long calc_fclk(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
{
unsigned int hf, vf;
@@ -1501,7 +2586,7 @@ static unsigned long calc_fclk(u16 width, u16 height,
vf = 1;
/* FIXME venc pclk? */
- return dispc_pclk_rate() * vf * hf;
+ return dispc_pclk_rate(channel) * vf * hf;
}
void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
@@ -1519,11 +2604,11 @@ static int _dispc_setup_plane(enum omap_plane plane,
enum omap_color_mode color_mode,
bool ilace,
enum omap_dss_rotation_type rotation_type,
- u8 rotation, int mirror,
- u8 global_alpha)
+ u8 rotation, int mirror, enum omap_channel channel,
+ u8 global_alpha, u32 puv_addr)
{
- const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
- bool five_taps = 0;
+ const int maxdownscale = (cpu_is_omap34xx() | cpu_is_omap44xx()) ? 4 : 2;
+ bool three_taps = 0;
bool fieldmode = 0;
int cconv = 0;
unsigned offset0, offset1;
@@ -1558,6 +2643,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
case OMAP_DSS_COLOR_RGBX32:
+
if (cpu_is_omap24xx())
return -EINVAL;
/* fall through */
@@ -1575,12 +2661,10 @@ static int _dispc_setup_plane(enum omap_plane plane,
unsigned long fclk = 0;
- if (out_width < width / maxdownscale ||
- out_width > width * 8)
+ if (out_width < width / maxdownscale)
return -EINVAL;
- if (out_height < height / maxdownscale ||
- out_height > height * 8)
+ if (out_height < height / maxdownscale)
return -EINVAL;
switch (color_mode) {
@@ -1597,12 +2681,18 @@ static int _dispc_setup_plane(enum omap_plane plane,
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
+ case OMAP_DSS_COLOR_RGBA12:
+ case OMAP_DSS_COLOR_XRGB12:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_RGBX24_32_ALGN:
+ case OMAP_DSS_COLOR_XRGB15:
if (cpu_is_omap24xx())
return -EINVAL;
- if (plane == OMAP_DSS_VIDEO1)
+ if (!cpu_is_omap44xx() && plane == OMAP_DSS_VIDEO1)
return -EINVAL;
break;
+ case OMAP_DSS_COLOR_NV12:
case OMAP_DSS_COLOR_YUV2:
case OMAP_DSS_COLOR_UYVY:
cconv = 1;
@@ -1612,32 +2702,36 @@ static int _dispc_setup_plane(enum omap_plane plane,
return -EINVAL;
}
- /* Must use 5-tap filter? */
- five_taps = height > out_height * 2;
+ /* Must use 3-tap filter */
+ three_taps = width > 1280;
- if (!five_taps) {
- fclk = calc_fclk(width, height,
+ /* Should use 3-tap filter for upscaling, but HDMI gets
+ out of sync if using 3-tap */
+ /* if (out_height > height)
+ three_taps = 1; */
+
+ if (three_taps) {
+ fclk = calc_fclk(channel, width, height,
out_width, out_height);
/* Try 5-tap filter if 3-tap fclk is too high */
if (cpu_is_omap34xx() && height > out_height &&
- fclk > dispc_fclk_rate())
- five_taps = true;
+ fclk > dispc_fclk_rate()) {
+ printk(KERN_ERR
+ "Should use 5 tap but cannot\n");
+ }
+ } else {
+ fclk = calc_fclk_five_taps(channel, width, height,
+ out_width, out_height, color_mode);
}
- if (width > (2048 >> five_taps)) {
- DSSERR("failed to set up scaling, fclk too low\n");
+ if (!cpu_is_omap44xx())
+ if (width > (1024 << three_taps))
return -EINVAL;
- }
-
- if (five_taps)
- fclk = calc_fclk_five_taps(width, height,
- out_width, out_height, color_mode);
-
DSSDBG("required fclk rate = %lu Hz\n", fclk);
DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
- if (!fclk || fclk > dispc_fclk_rate()) {
+ if (fclk > dispc_fclk_rate()) {
DSSERR("failed to set up scaling, "
"required fclk rate = %lu Hz, "
"current fclk rate = %lu Hz\n",
@@ -1663,18 +2757,73 @@ static int _dispc_setup_plane(enum omap_plane plane,
/* Fields are independent but interleaved in memory. */
if (fieldmode)
field_offset = 1;
+ pix_inc = 0x1;
+ offset0 = 0x0;
+ offset1 = 0x0;
+ /* check if tiler address; else set row_inc = 1*/
+ if ((paddr >= 0x60000000) && (paddr <= 0x7fffffff)) {
+ struct tiler_view_orient orient;
+ u8 mir_x = 0, mir_y = 0;
+ unsigned long tiler_width, tiler_height;
+
+ calc_tiler_row_rotation(rotation, width, frame_height,
+ color_mode, &row_inc);
+
+ /* get rotated top-left coordinate
+ (if rotation is applied before mirroring) */
+ memset(&orient, 0, sizeof(orient));
+
+ if (rotation & 1)
+ rotation ^= 2;
+
+ tiler_rotate_view(&orient, rotation * 90);
+
+ if (mirror) {
+ if (rotation & 1)
+ mir_x = 1;
+ else
+ mir_y = 1;
+ }
+ orient.x_invert ^= mir_x;
+ orient.y_invert ^= mir_y;
- if (rotation_type == OMAP_DSS_ROT_DMA)
- calc_dma_rotation_offset(rotation, mirror,
+ DSSDBG("RXY = %d %d %d\n", orient.rotate_90,
+ orient.x_invert, orient.y_invert);
+
+ if (orient.rotate_90 & 1) {
+ tiler_height = width;
+ tiler_width = height;
+ } else {
+ tiler_height = height;
+ tiler_width = width;
+ }
+ DSSDBG("w, h = %ld %ld\n", tiler_width, tiler_height);
+
+ paddr = tiler_reorient_topleft(tiler_get_natural_addr((void *)paddr),
+ orient, tiler_width, tiler_height);
+
+ if (puv_addr)
+ puv_addr = tiler_reorient_topleft(
+ tiler_get_natural_addr((void *)puv_addr),
+ orient, tiler_width/2, tiler_height/2);
+ DSSDBG("rotated addresses: 0x%0x, 0x%0x\n",
+ paddr, puv_addr);
+ /* set BURSTTYPE if rotation is non-zero */
+ REG_FLD_MOD(dispc_reg_att[plane], 0x1, 29, 29);
+ } else
+ row_inc = 0x1;
+ if (!cpu_is_omap44xx()) {
+ if (rotation_type == OMAP_DSS_ROT_DMA)
+ calc_dma_rotation_offset(rotation, mirror,
screen_width, width, frame_height, color_mode,
fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc);
- else
- calc_vrfb_rotation_offset(rotation, mirror,
+ else
+ calc_vrfb_rotation_offset(rotation, mirror,
screen_width, width, frame_height, color_mode,
fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc);
-
+ }
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
@@ -1683,6 +2832,11 @@ static int _dispc_setup_plane(enum omap_plane plane,
_dispc_set_plane_ba0(plane, paddr + offset0);
_dispc_set_plane_ba1(plane, paddr + offset1);
+ if (OMAP_DSS_COLOR_NV12 == color_mode) {
+ _dispc_set_plane_ba_uv0(plane, puv_addr + offset0);
+ _dispc_set_plane_ba_uv1(plane, puv_addr + offset1);
+ }
+
_dispc_set_row_inc(plane, row_inc);
_dispc_set_pix_inc(plane, pix_inc);
@@ -1694,16 +2848,56 @@ static int _dispc_setup_plane(enum omap_plane plane,
_dispc_set_pic_size(plane, width, height);
if (plane != OMAP_DSS_GFX) {
+ int scale_x = width != out_width;
+ int scale_y = height != out_height;
+ u16 out_ch_height = out_height;
+ u16 out_ch_width = out_width;
+ u16 ch_height = height;
+ u16 ch_width = width;
+ int scale_uv = 0;
+
+ if (cpu_is_omap44xx()) {
+ /* account for chroma decimation */
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ ch_height >>= 1; /* Y downsampled by 2 */
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ ch_width >>= 1; /* X downsampled by 2 */
+ /* must use FIR for YUV422 if rotated */
+ if (color_mode != OMAP_DSS_COLOR_NV12 && rotation % 4)
+ scale_x = scale_y = 1;
+ scale_uv = 1;
+ break;
+ default:
+ /* no UV scaling for RGB formats for now */
+ break;
+ }
+
+ if (out_ch_width != ch_width)
+ scale_x = true;
+ if (out_ch_height != ch_height)
+ scale_y = true;
+ /* set up UV scaling */
+ _dispc_set_scaling_uv(plane, ch_width, ch_height,
+ out_ch_width, out_ch_height, ilace,
+ three_taps, fieldmode, scale_uv && scale_x,
+ scale_uv && scale_y);
+ if (!scale_uv || (!scale_x && !scale_y))
+ /* :TRICKY: set chroma resampling for RGB formats */
+ REG_FLD_MOD(DISPC_VID_ATTRIBUTES2(plane - 1), 0, 8, 8);
+ }
_dispc_set_scaling(plane, width, height,
out_width, out_height,
- ilace, five_taps, fieldmode);
+ ilace, three_taps, fieldmode,
+ scale_x, scale_y);
_dispc_set_vid_size(plane, out_width, out_height);
_dispc_set_vid_color_conv(plane, cconv);
}
_dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
- if (plane != OMAP_DSS_VIDEO1)
+ if ((plane != OMAP_DSS_VIDEO1) || (cpu_is_omap44xx()))
_dispc_setup_global_alpha(plane, global_alpha);
return 0;
@@ -1712,6 +2906,10 @@ static int _dispc_setup_plane(enum omap_plane plane,
static void _dispc_enable_plane(enum omap_plane plane, bool enable)
{
REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
+ if (!enable && cpu_is_omap44xx()) { /* clear out resizer related bits */
+ REG_FLD_MOD(dispc_reg_att[plane], 0x00, 6, 5);
+ REG_FLD_MOD(dispc_reg_att[plane], 0x00, 21, 21);
+ }
}
static void dispc_disable_isr(void *data, u32 mask)
@@ -1720,36 +2918,47 @@ static void dispc_disable_isr(void *data, u32 mask)
complete(compl);
}
-static void _enable_lcd_out(bool enable)
+static void _enable_lcd_out(enum omap_channel channel, bool enable)
{
- REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
}
-static void dispc_enable_lcd_out(bool enable)
+void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
{
struct completion frame_done_completion;
bool is_on;
int r;
+ int irq;
enable_clocks(1);
/* When we disable LCD output, we need to wait until frame is done.
* Otherwise the DSS is still working, and turning off the clocks
* prevents DSS from going to OFF mode */
- is_on = REG_GET(DISPC_CONTROL, 0, 0);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel) {
+ is_on = REG_GET(DISPC_CONTROL2, 0, 0);
+ irq = DISPC_IRQ_FRAMEDONE2;
+ } else {
+ is_on = REG_GET(DISPC_CONTROL, 0, 0);
+ irq = DISPC_IRQ_FRAMEDONE;
+ }
+
if (!enable && is_on) {
init_completion(&frame_done_completion);
r = omap_dispc_register_isr(dispc_disable_isr,
&frame_done_completion,
- DISPC_IRQ_FRAMEDONE);
+ irq);
if (r)
DSSERR("failed to register FRAMEDONE isr\n");
}
- _enable_lcd_out(enable);
+ _enable_lcd_out(channel, enable);
if (!enable && is_on) {
if (!wait_for_completion_timeout(&frame_done_completion,
@@ -1758,7 +2967,7 @@ static void dispc_enable_lcd_out(bool enable)
r = omap_dispc_unregister_isr(dispc_disable_isr,
&frame_done_completion,
- DISPC_IRQ_FRAMEDONE);
+ irq);
if (r)
DSSERR("failed to unregister FRAMEDONE isr\n");
@@ -1772,7 +2981,7 @@ static void _enable_digit_out(bool enable)
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
}
-static void dispc_enable_digit_out(bool enable)
+void dispc_enable_digit_out(bool enable)
{
struct completion frame_done_completion;
int r;
@@ -1810,13 +3019,15 @@ static void dispc_enable_digit_out(bool enable)
/* XXX I understand from TRM that we should only wait for the
* current field to complete. But it seems we have to wait
* for both fields */
- if (!wait_for_completion_timeout(&frame_done_completion,
+ if (!cpu_is_omap44xx()) {
+ if (!wait_for_completion_timeout(&frame_done_completion,
msecs_to_jiffies(100)))
- DSSERR("timeout waiting for EVSYNC\n");
+ DSSERR("timeout waiting for EVSYNC\n");
- if (!wait_for_completion_timeout(&frame_done_completion,
+ if (!wait_for_completion_timeout(&frame_done_completion,
msecs_to_jiffies(100)))
- DSSERR("timeout waiting for EVSYNC\n");
+ DSSERR("timeout waiting for EVSYNC\n");
+ }
r = omap_dispc_unregister_isr(dispc_disable_isr,
&frame_done_completion,
@@ -1848,8 +3059,9 @@ bool dispc_is_channel_enabled(enum omap_channel channel)
void dispc_enable_channel(enum omap_channel channel, bool enable)
{
- if (channel == OMAP_DSS_CHANNEL_LCD)
- dispc_enable_lcd_out(enable);
+ if (channel == OMAP_DSS_CHANNEL_LCD ||
+ channel == OMAP_DSS_CHANNEL_LCD2)
+ dispc_enable_lcd_out(channel, enable);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
dispc_enable_digit_out(enable);
else
@@ -1885,7 +3097,8 @@ void dispc_enable_fifohandcheck(bool enable)
}
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
+void dispc_set_lcd_display_type(enum omap_channel channel,
+ enum omap_lcd_display_type type)
{
int mode;
@@ -1904,7 +3117,11 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
}
enable_clocks(1);
- REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
+
enable_clocks(0);
}
@@ -1919,8 +3136,7 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
void dispc_set_default_color(enum omap_channel channel, u32 color)
{
const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
- DISPC_DEFAULT_COLOR1 };
-
+ DISPC_DEFAULT_COLOR1, DISPC_DEFAULT_COLOR2 };
enable_clocks(1);
dispc_write_reg(def_reg[channel], color);
enable_clocks(0);
@@ -1929,11 +3145,12 @@ void dispc_set_default_color(enum omap_channel channel, u32 color)
u32 dispc_get_default_color(enum omap_channel channel)
{
const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
- DISPC_DEFAULT_COLOR1 };
+ DISPC_DEFAULT_COLOR1, DISPC_DEFAULT_COLOR2 };
u32 l;
- BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
- channel != OMAP_DSS_CHANNEL_LCD);
+ if (!cpu_is_omap44xx())
+ BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
+ channel != OMAP_DSS_CHANNEL_LCD);
enable_clocks(1);
l = dispc_read_reg(def_reg[channel]);
@@ -1947,10 +3164,13 @@ void dispc_set_trans_key(enum omap_channel ch,
u32 trans_key)
{
const struct dispc_reg tr_reg[] = {
- DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
+ DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1,
+ DISPC_TRANS_COLOR2};
enable_clocks(1);
- if (ch == OMAP_DSS_CHANNEL_LCD)
+ if (ch == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
+ else if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
else /* OMAP_DSS_CHANNEL_DIGIT */
REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
@@ -1964,11 +3184,14 @@ void dispc_get_trans_key(enum omap_channel ch,
u32 *trans_key)
{
const struct dispc_reg tr_reg[] = {
- DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
+ DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1,
+ DISPC_TRANS_COLOR2 };
enable_clocks(1);
if (type) {
- if (ch == OMAP_DSS_CHANNEL_LCD)
+ if (ch == OMAP_DSS_CHANNEL_LCD2)
+ *type = REG_GET(DISPC_CONFIG2, 11, 11);
+ else if (ch == OMAP_DSS_CHANNEL_LCD)
*type = REG_GET(DISPC_CONFIG, 11, 11);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
*type = REG_GET(DISPC_CONFIG, 13, 13);
@@ -1984,7 +3207,9 @@ void dispc_get_trans_key(enum omap_channel ch,
void dispc_enable_trans_key(enum omap_channel ch, bool enable)
{
enable_clocks(1);
- if (ch == OMAP_DSS_CHANNEL_LCD)
+ if (ch == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
+ else if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
else /* OMAP_DSS_CHANNEL_DIGIT */
REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
@@ -2026,8 +3251,12 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
bool dispc_trans_key_enabled(enum omap_channel ch)
{
bool enabled;
+ BUG_ON(ch == OMAP_DSS_CHANNEL_LCD2);
enable_clocks(1);
+ if (ch == OMAP_DSS_CHANNEL_LCD2)
+ enabled = REG_GET(DISPC_CONFIG2, 10, 10);
+ else
if (ch == OMAP_DSS_CHANNEL_LCD)
enabled = REG_GET(DISPC_CONFIG, 10, 10);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2040,7 +3269,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
}
-void dispc_set_tft_data_lines(u8 data_lines)
+void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
{
int code;
@@ -2063,11 +3292,15 @@ void dispc_set_tft_data_lines(u8 data_lines)
}
enable_clocks(1);
- REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
enable_clocks(0);
}
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+ enum omap_parallel_interface_mode mode)
{
u32 l;
int stallmode;
@@ -2097,13 +3330,18 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
enable_clocks(1);
- l = dispc_read_reg(DISPC_CONTROL);
-
- l = FLD_MOD(l, stallmode, 11, 11);
- l = FLD_MOD(l, gpout0, 15, 15);
- l = FLD_MOD(l, gpout1, 16, 16);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel) {
+ l = dispc_read_reg(DISPC_CONTROL2);
+ l = FLD_MOD(l, stallmode, 11, 11);
+ dispc_write_reg(DISPC_CONTROL2, l);
+ } else {
+ l = dispc_read_reg(DISPC_CONTROL);
+ l = FLD_MOD(l, stallmode, 11, 11);
+ l = FLD_MOD(l, gpout0, 15, 15);
+ l = FLD_MOD(l, gpout1, 16, 16);
- dispc_write_reg(DISPC_CONTROL, l);
+ dispc_write_reg(DISPC_CONTROL, l);
+ }
enable_clocks(0);
}
@@ -2139,8 +3377,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
timings->vfp, timings->vbp);
}
-static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
- int vsw, int vfp, int vbp)
+static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
+ int hfp, int hbp, int vsw, int vfp, int vbp)
{
u32 timing_h, timing_v;
@@ -2159,13 +3397,19 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
}
enable_clocks(1);
- dispc_write_reg(DISPC_TIMING_H, timing_h);
- dispc_write_reg(DISPC_TIMING_V, timing_v);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel) {
+ dispc_write_reg(DISPC_TIMING_H2, timing_h);
+ dispc_write_reg(DISPC_TIMING_V2, timing_v);
+ } else {
+ dispc_write_reg(DISPC_TIMING_H, timing_h);
+ dispc_write_reg(DISPC_TIMING_V, timing_v);
+ }
enable_clocks(0);
}
/* change name to mode? */
-void dispc_set_lcd_timings(struct omap_video_timings *timings)
+void dispc_set_lcd_timings(enum omap_channel channel,
+ struct omap_video_timings *timings)
{
unsigned xtot, ytot;
unsigned long ht, vt;
@@ -2175,10 +3419,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
timings->vfp, timings->vbp))
BUG();
- _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
- timings->vsw, timings->vfp, timings->vbp);
+ _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
+ timings->hbp, timings->vsw, timings->vfp,
+ timings->vbp);
- dispc_set_lcd_size(timings->x_res, timings->y_res);
+ dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
@@ -2186,7 +3431,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
ht = (timings->pixel_clock * 1000) / xtot;
vt = (timings->pixel_clock * 1000) / xtot / ytot;
- DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
+ DSSDBG("channel %u xres %u yres %u\n", channel, timings->x_res,
+ timings->y_res);
DSSDBG("pck %u\n", timings->pixel_clock);
DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
timings->hsw, timings->hfp, timings->hbp,
@@ -2195,21 +3441,30 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
}
-static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
+static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
+ u16 pck_div)
{
BUG_ON(lck_div < 1);
BUG_ON(pck_div < 2);
enable_clocks(1);
- dispc_write_reg(DISPC_DIVISOR,
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ dispc_write_reg(DISPC_DIVISOR2,
+ FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
+ else
+ dispc_write_reg(DISPC_DIVISOR,
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
enable_clocks(0);
}
-static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
+static void dispc_get_lcd_divisor(enum omap_channel channel,
+ int *lck_div, int *pck_div)
{
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ l = dispc_read_reg(DISPC_DIVISOR2);
+ else
+ l = dispc_read_reg(DISPC_DIVISOR);
*lck_div = FLD_GET(l, 23, 16);
*pck_div = FLD_GET(l, 7, 0);
}
@@ -2222,20 +3477,22 @@ unsigned long dispc_fclk_rate(void)
r = dss_clk_get_rate(DSS_CLK_FCK1);
else
#ifdef CONFIG_OMAP2_DSS_DSI
- r = dsi_get_dsi1_pll_rate();
+ r = dsi_get_dsi1_pll_rate(DSI1);
#else
BUG();
#endif
return r;
}
-unsigned long dispc_lclk_rate(void)
+unsigned long dispc_lclk_rate(enum omap_channel channel)
{
int lcd;
unsigned long r;
u32 l;
-
- l = dispc_read_reg(DISPC_DIVISOR);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ l = dispc_read_reg(DISPC_DIVISOR2);
+ else
+ l = dispc_read_reg(DISPC_DIVISOR);
lcd = FLD_GET(l, 23, 16);
@@ -2244,13 +3501,16 @@ unsigned long dispc_lclk_rate(void)
return r / lcd;
}
-unsigned long dispc_pclk_rate(void)
+unsigned long dispc_pclk_rate(enum omap_channel channel)
{
int lcd, pcd;
unsigned long r;
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR);
+ if (OMAP_DSS_CHANNEL_LCD2 == channel)
+ l = dispc_read_reg(DISPC_DIVISOR2);
+ else
+ l = dispc_read_reg(DISPC_DIVISOR);
lcd = FLD_GET(l, 23, 16);
pcd = FLD_GET(l, 7, 0);
@@ -2266,7 +3526,7 @@ void dispc_dump_clocks(struct seq_file *s)
enable_clocks(1);
- dispc_get_lcd_divisor(&lcd, &pcd);
+ dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
seq_printf(s, "- DISPC -\n");
@@ -2275,8 +3535,26 @@ void dispc_dump_clocks(struct seq_file *s)
"dss1_alwon_fclk" : "dsi1_pll_fclk");
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
- seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
- seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
+ seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
+
+ if (cpu_is_omap44xx()) {
+ dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
+
+ seq_printf(s, "- DISPC - LCD 2\n");
+
+ seq_printf(s, "dispc fclk source = %s\n",
+ dss_get_dispc_clk_source() == 0 ?
+ "dss1_alwon_fclk" : "dsi1_pll_fclk");
+
+ seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
+ seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
+ }
enable_clocks(0);
}
@@ -2392,6 +3670,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_VID_POSITION(1));
DUMPREG(DISPC_VID_SIZE(1));
DUMPREG(DISPC_VID_ATTRIBUTES(1));
+ DUMPREG(DISPC_VID_V3_WB_ATTRIBUTES(1));
DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
DUMPREG(DISPC_VID_ROW_INC(1));
@@ -2468,8 +3747,9 @@ void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
- bool ihs, bool ivs, u8 acbi, u8 acb)
+static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
+ bool ieo, bool ipc, bool ihs, bool ivs,
+ u8 acbi, u8 acb)
{
u32 l = 0;
@@ -2486,13 +3766,17 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
l |= FLD_VAL(acb, 7, 0);
enable_clocks(1);
- dispc_write_reg(DISPC_POL_FREQ, l);
+ if (OMAP_DSS_CHANNEL_LCD2)
+ dispc_write_reg(DISPC_POL_FREQ2, l);
+ else
+ dispc_write_reg(DISPC_POL_FREQ, l);
enable_clocks(0);
}
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
+void dispc_set_pol_freq(enum omap_channel ch, enum omap_panel_config config,
+ u8 acbi, u8 acb)
{
- _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
+ _dispc_set_pol_freq(ch, (config & OMAP_DSS_LCD_ONOFF) != 0,
(config & OMAP_DSS_LCD_RF) != 0,
(config & OMAP_DSS_LCD_IEO) != 0,
(config & OMAP_DSS_LCD_IPC) != 0,
@@ -2561,25 +3845,31 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
return 0;
}
-int dispc_set_clock_div(struct dispc_clock_info *cinfo)
+int dispc_set_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo)
{
DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
- dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
+ dispc_set_lcd_divisor(channel, cinfo->lck_div,
+ cinfo->pck_div);
return 0;
}
-int dispc_get_clock_div(struct dispc_clock_info *cinfo)
+int dispc_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo)
{
unsigned long fck;
fck = dispc_fclk_rate();
-
- cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
- cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
-
+ if (OMAP_DSS_CHANNEL_LCD2 == channel) {
+ cinfo->lck_div = REG_GET(DISPC_DIVISOR2, 23, 16);
+ cinfo->pck_div = REG_GET(DISPC_DIVISOR2, 7, 0);
+ } else {
+ cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
+ cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
+ }
cinfo->lck = fck / cinfo->lck_div;
cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2857,6 +4147,23 @@ static void dispc_error_worker(struct work_struct *work)
}
}
}
+ if (errors & DISPC_IRQ_VID3_FIFO_UNDERFLOW) {
+ DSSERR("VID3_FIFO_UNDERFLOW, disabling VID2\n");
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(i);
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ if (ovl->id == 3) {
+ dispc_enable_plane(ovl->id, 0);
+ dispc_go(ovl->manager->id);
+ mdelay(50);
+ break;
+ }
+ }
+ }
if (errors & DISPC_IRQ_SYNC_LOST) {
struct omap_overlay_manager *manager = NULL;
@@ -2897,7 +4204,52 @@ static void dispc_error_worker(struct work_struct *work)
}
}
+ if (errors & DISPC_IRQ_SYNC_LOST_2) {
+ struct omap_overlay_manager *manager = NULL;
+ bool enable = false;
+
+ DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
+
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ struct omap_overlay_manager *mgr;
+ mgr = omap_dss_get_overlay_manager(i);
+
+ if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
+ manager = mgr;
+ enable = mgr->device->state ==
+ OMAP_DSS_DISPLAY_ACTIVE;
+ mgr->device->driver->disable(mgr->device);
+ break;
+ }
+ }
+
+ if (manager) {
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(i);
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ if (ovl->id != 0 && ovl->manager == manager)
+ dispc_enable_plane(ovl->id, 0);
+ }
+
+ dispc_go(manager->id);
+ mdelay(50);
+ if (enable)
+ manager->device->driver->enable(
+ manager->device);
+ }
+ }
+
+
if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
+
+ DSSERR("SYNC_LOST_DIGIT\n");
+/*commenting below code as with 1080P Decode we see a sync lost digit for
+first frame as it takes long time to decode but it later recovers*/
+#if 0
struct omap_overlay_manager *manager = NULL;
bool enable = false;
@@ -2914,6 +4266,7 @@ static void dispc_error_worker(struct work_struct *work)
mgr->device->driver->disable(mgr->device);
break;
}
+
}
if (manager) {
@@ -2934,6 +4287,7 @@ static void dispc_error_worker(struct work_struct *work)
if (enable)
dssdev->driver->enable(dssdev);
}
+#endif
}
if (errors & DISPC_IRQ_OCP_ERR) {
@@ -3014,13 +4368,24 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
}
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
-void dispc_fake_vsync_irq(void)
+void dispc_fake_vsync_irq(enum omap_dsi_index ix)
{
u32 irqstatus = DISPC_IRQ_VSYNC;
int i;
local_irq_disable();
-
+ switch (ix) {
+ case DSI1:
+ irqstatus = DISPC_IRQ_VSYNC;
+ break;
+ case DSI2:
+ irqstatus = DISPC_IRQ_VSYNC2;
+ break;
+ default:
+ DSSERR("Invalid display id for fake vsync\n");
+ local_irq_enable();
+ return;
+ }
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
struct omap_dispc_isr_data *isr_data;
isr_data = &dispc.registered_isr[i];
@@ -3077,7 +4442,8 @@ static void _omap_dispc_initial_config(void)
dispc_write_reg(DISPC_SYSCONFIG, l);
/* FUNCGATED */
- REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
+ if (!cpu_is_omap44xx())
+ REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
/* L3 firewall setting: enable access to OCM RAM */
/* XXX this should be somewhere in plat-omap */
@@ -3104,7 +4470,7 @@ int dispc_init(void)
INIT_WORK(&dispc.error_work, dispc_error_worker);
- dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
+ dispc_base = dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
if (!dispc.base) {
DSSERR("can't ioremap DISPC\n");
return -ENOMEM;
@@ -3151,7 +4517,8 @@ int dispc_setup_plane(enum omap_plane plane,
enum omap_color_mode color_mode,
bool ilace,
enum omap_dss_rotation_type rotation_type,
- u8 rotation, bool mirror, u8 global_alpha)
+ u8 rotation, bool mirror, u8 global_alpha,
+ enum omap_channel channel, u32 puv_addr)
{
int r = 0;
@@ -3173,9 +4540,246 @@ int dispc_setup_plane(enum omap_plane plane,
color_mode, ilace,
rotation_type,
rotation, mirror,
- global_alpha);
+ channel,
+ global_alpha,
+ puv_addr);
enable_clocks(0);
return r;
}
+
+/* Writeback*/
+int dispc_setup_wb(struct writeback_cache_data *wb)
+{
+ unsigned long mir_x, mir_y;
+ unsigned long tiler_width, tiler_height;
+ u8 orientation = 0, rotation = 0, mirror = 0 ;
+ int ch_width, ch_height, out_ch_width, out_ch_height, scale_x, scale_y;
+ struct tiler_view_orient orient;
+ u32 paddr = wb->paddr;
+ u32 puv_addr = wb->puv_addr; /* relevant for NV12 format only */
+ u16 out_width = wb->width;
+ u16 out_height = wb->height;
+ u16 width = wb->input_width;
+ u16 height = wb->input_height;
+
+ enum omap_color_mode color_mode = wb->color_mode; /* output color */
+
+ u32 fifo_low = wb->fifo_low;
+ u32 fifo_high = wb->fifo_high;
+ enum omap_writeback_source source = wb->source;
+
+ enum omap_plane plane = OMAP_DSS_WB;
+ enum omap_plane input_plane;
+
+ const int maxdownscale = 2;
+ bool three_taps = 0;
+ int cconv = 0;
+ s32 row_inc;
+ s32 pix_inc;
+ u16 frame_height = height;
+
+ DSSDBG("dispc_setup_wb");
+ DSSDBG("Maxds = %d", maxdownscale);
+ DSSDBG("out_width, width = %d, %d", (int) out_width, (int) width);
+ DSSDBG("out_height, height = %d, %d", (int) out_height, (int) height);
+
+ if (paddr == 0) {
+ printk("KERN_ERR dispc_setup_wb paddr NULL");
+ return -EINVAL;
+ }
+ {
+ /* validate color format and 5taps*/
+
+ if (out_width < width / maxdownscale ||
+ out_width > width * 8){
+ printk("KERN_ERR dispc_setup_wb out_width not in range ");
+ return -EINVAL;
+ }
+ if (out_height < height / maxdownscale ||
+ out_height > height * 8){
+ printk("KERN_ERR dispc_setup_wb out_height not in range ");
+ return -EINVAL;
+ }
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_RGB24P:
+ case OMAP_DSS_COLOR_RGB24U:
+ case OMAP_DSS_COLOR_ARGB16:
+ case OMAP_DSS_COLOR_ARGB32:
+ case OMAP_DSS_COLOR_RGBA32:
+ case OMAP_DSS_COLOR_RGBA12:
+ case OMAP_DSS_COLOR_XRGB12:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_RGBX24_32_ALGN:
+ case OMAP_DSS_COLOR_XRGB15:
+ break;
+
+ case OMAP_DSS_COLOR_NV12:
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ cconv = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (width > 1280)
+ three_taps = 1;
+
+/* we handle ONLY overlays as source yet, NOT Managers */
+/* TODO: remove this check once managers are accepted as source */
+ if (source > OMAP_WB_TV_MANAGER) {
+ input_plane = (source - 3);
+
+ DSSDBG("input pipeline is not an overlay manager so overlay %d is configured ", input_plane);
+ /* Set the channel out for input source: DISPC_VIDX_ATTRIBUTES[31:30] CHANNELOUT2 as WB (0x3)*/
+ REG_FLD_MOD(dispc_reg_att[input_plane], 0x3, 31, 30);
+ /* Set the channel out for input source: DISPC_VIDX_ATTRIBUTES[16] CHANNELOUT as LCD / WB (0x0)*/
+ REG_FLD_MOD(dispc_reg_att[input_plane], 0x0, 16, 16);
+
+ REG_FLD_MOD(dispc_reg_att[input_plane], 0x1, 10, 10);
+ REG_FLD_MOD(dispc_reg_att[input_plane], 0x1, 19, 19);
+ REG_FLD_MOD(dispc_reg_att[plane], source, 18, 16);
+#ifdef OMAP4430_REV_ES2_0
+ /* Memory to memory mode bit is set on ES 2.0 */
+ REG_FLD_MOD(dispc_reg_att[plane], 1, 19, 19);
+#endif
+ }
+
+ pix_inc = 0x1;
+ if ((paddr >= 0x60000000) && (paddr <= 0x7fffffff)) {
+ calc_tiler_row_rotation(rotation, width, frame_height,
+ color_mode, &row_inc);
+ orientation = calc_tiler_orientation(rotation, (u8)mirror);
+ /* get rotated top-left coordinate
+ (if rotation is applied before mirroring) */
+ memset(&orient, 0, sizeof(orient));
+ tiler_rotate_view(&orient, rotation * 90);
+
+ if (mirror) {
+ /* Horizontal mirroring */
+ if (rotation == 1 || rotation == 3)
+ mir_x = 1;
+ else
+ mir_y = 1;
+ } else {
+ mir_x = 0;
+ mir_y = 0;
+ }
+ orient.x_invert ^= mir_x;
+ orient.y_invert ^= mir_y;
+
+ if (orient.rotate_90 & 1) {
+ tiler_height = width;
+ tiler_width = height;
+ } else {
+ tiler_height = height;
+ tiler_width = width;
+ }
+
+ paddr = tiler_reorient_topleft(tiler_get_natural_addr((void *)paddr),
+ orient, tiler_width, tiler_height);
+
+ if (puv_addr)
+ puv_addr = tiler_reorient_topleft(
+ tiler_get_natural_addr((void *)puv_addr),
+ orient, tiler_width/2, tiler_height/2);
+ DSSDBG(
+ "rotated addresses: 0x%0x, 0x%0x\n",
+ paddr, puv_addr);
+ /* set BURSTTYPE if rotation is non-zero */
+ REG_FLD_MOD(dispc_reg_att[plane], 0x1, 8, 8);
+ } else
+ row_inc = 1;
+
+
+ _dispc_set_color_mode(plane, color_mode);
+
+ _dispc_set_plane_ba0(plane, paddr);
+ _dispc_set_plane_ba1(plane, paddr);
+ if (OMAP_DSS_COLOR_NV12 == color_mode) {
+ _dispc_set_plane_ba_uv0(plane, puv_addr);
+ _dispc_set_plane_ba_uv1(plane, puv_addr);
+ }
+ _dispc_set_row_inc(plane, row_inc);
+ _dispc_set_pix_inc(plane, pix_inc);
+
+ DSSDBG("%dx%d -> %p,%p %dx%d\n",
+ width, height,
+ (void *)paddr, (void *)puv_addr, out_width, out_height);
+
+ _dispc_set_pic_size(plane, width, height);
+ dispc_setup_plane_fifo(plane, fifo_low, fifo_high);
+
+ /* non interlaced */
+ ch_width = width;
+ ch_height = height;
+ out_ch_width = out_width;
+ out_ch_height = out_height;
+
+ /* account for output color decimation */
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ out_ch_height >>= 1;
+ case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_YUV2:
+ out_ch_width >>= 1;
+ default:
+ ;
+ }
+
+ /* account for input color decimation */
+ switch (wb->input_color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ ch_height >>= 1;
+ case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_YUV2:
+ ch_width >>= 1;
+ default:
+ ;
+ }
+
+ /* we must scale NV12 format */
+ scale_x = width != out_width || ch_width != out_ch_width;
+ scale_y = height != out_height || ch_height != out_ch_height;
+ _dispc_set_scaling(plane, width, height,
+ out_width, out_height,
+ 0, three_taps, false, scale_x, scale_y);
+
+ if (out_ch_width != out_width) {
+ /* this is true for YUV formats */
+ _dispc_set_scaling_uv(plane, ch_width, ch_height,
+ out_ch_width, out_ch_height, 0,
+ three_taps, false, scale_x, scale_y);
+ } else {
+ /* set chroma resampling */
+ REG_FLD_MOD(DISPC_VID_ATTRIBUTES2(plane - 1), 0, 8, 8);
+ }
+
+ _dispc_set_vid_size(plane, out_width, out_height);
+ _dispc_set_vid_color_conv(plane, cconv);
+
+ pix_inc = dispc_read_reg(dispc_reg_att[plane]);
+ DSSDBG("vid[%d] attributes = %x\n", plane, pix_inc);
+
+ return 0;
+
+}
+
+void dispc_go_wb(void)
+{
+ enable_clocks(1);
+
+ if (REG_GET(DISPC_CONTROL2, 6, 6) == 1) {
+ DSSERR("GO bit not down for WB\n");
+ goto end;
+ }
+ REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
+ DSSDBG("dispc_go_wb\n");
+end:
+ enable_clocks(0);
+}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 6a74ea116d29..05801825394e 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -29,6 +29,7 @@
#include <linux/platform_device.h>
#include <plat/display.h>
+#include <plat/cpu.h>
#include "dss.h"
static LIST_HEAD(display_list);
@@ -278,6 +279,55 @@ static ssize_t display_wss_store(struct device *dev,
return size;
}
+static ssize_t display_edid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+
+
+ if (!dssdev->driver->get_edid)
+ return -ENOENT;
+ dssdev->driver->get_edid(dssdev);
+ return snprintf(buf, PAGE_SIZE, "EDID-Information");
+
+}
+static ssize_t display_custom_edid_timing_store(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ int val, code, mode;
+ val = simple_strtoul(buf, NULL, 0);
+ code = val / 10;
+ mode = val % 10;
+ if (!dssdev->driver->set_custom_edid_timing_code)
+ return -ENOENT;
+ dssdev->driver->set_custom_edid_timing_code(dssdev, code, mode);
+ return snprintf(buf, PAGE_SIZE, "EDID-Information %d mode % d code", mode, code);
+
+}
+
+static ssize_t display_hpd_enabled_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ bool enabled, r;
+
+ enabled = simple_strtoul(buf, NULL, 10);
+
+ if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
+ if (enabled) {
+ r = dssdev->driver->hpd_enable(dssdev);
+ if (r)
+ return r;
+ } else {
+ dssdev->driver->disable(dssdev);
+ }
+ }
+
+ return size;
+}
+
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store);
static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
@@ -292,6 +342,10 @@ static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
display_mirror_show, display_mirror_store);
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
display_wss_show, display_wss_store);
+static DEVICE_ATTR(custom_edid_timing, S_IRUGO|S_IWUSR,
+ display_edid_show, display_custom_edid_timing_store);
+static DEVICE_ATTR(hpd_enabled, S_IRUGO|S_IWUSR,
+ NULL, display_hpd_enabled_store);
static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_enabled,
@@ -301,6 +355,8 @@ static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_rotate,
&dev_attr_mirror,
&dev_attr_wss,
+ &dev_attr_custom_edid_timing,
+ &dev_attr_hpd_enabled,
NULL
};
@@ -319,7 +375,11 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
unsigned burst_size_bytes;
*burst_size = OMAP_DSS_BURST_16x32;
- burst_size_bytes = 16 * 32 / 8;
+ if (cpu_is_omap44xx())
+ burst_size_bytes = 8 * 128 / 8; /* OMAP4: highest
+ burst size is 8x128*/
+ else
+ burst_size_bytes = 16 * 32 / 8;
*fifo_high = fifo_size - 1;
*fifo_low = fifo_size - burst_size_bytes;
@@ -342,7 +402,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
return 16;
case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_SDI:
- return 24;
+ case OMAP_DISPLAY_TYPE_HDMI:
return 24;
default:
BUG();
@@ -365,6 +425,9 @@ bool dss_use_replication(struct omap_dss_device *dssdev,
(dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
return false;
+ if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
+ return false;
+
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
bpp = dssdev->phy.dpi.data_lines;
@@ -392,7 +455,9 @@ void dss_init_device(struct platform_device *pdev,
int r;
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
#endif
@@ -405,6 +470,9 @@ void dss_init_device(struct platform_device *pdev,
#ifdef CONFIG_OMAP2_DSS_VENC
case OMAP_DISPLAY_TYPE_VENC:
#endif
+#ifdef CONFIG_OMAP2_DSS_HDMI
+ case OMAP_DISPLAY_TYPE_HDMI:
+#endif
break;
default:
DSSERR("Support for display '%s' not compiled in.\n",
@@ -413,9 +481,11 @@ void dss_init_device(struct platform_device *pdev,
}
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
break;
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
r = rfbi_init_display(dssdev);
@@ -436,6 +506,11 @@ void dss_init_device(struct platform_device *pdev,
r = dsi_init_display(dssdev);
break;
#endif
+#ifdef CONFIG_OMAP2_DSS_HDMI
+ case OMAP_DISPLAY_TYPE_HDMI:
+ r = hdmi_init_display(dssdev);
+ break;
+#endif
default:
BUG();
}
@@ -541,7 +616,10 @@ int dss_resume_all_devices(void)
static int dss_disable_device(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- dssdev->driver->disable(dssdev);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+ dssdev->driver->disable(dssdev);
+
return 0;
}
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 960e977a8bf0..971ee171a82d 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -40,25 +40,35 @@ static struct {
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
+static int dpi_set_dsi_clk(int lcd_channel_ix, bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
{
struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
int r;
-
- r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
+ if (!cpu_is_omap44xx()) {
+ r = dsi_pll_calc_clock_div_pck(lcd_channel_ix, is_tft, pck_req, &dsi_cinfo,
&dispc_cinfo);
if (r)
return r;
-
- r = dsi_pll_set_clock_div(&dsi_cinfo);
+ } else {
+ dispc_cinfo.lck_div = 1;
+ dispc_cinfo.pck_div = 4;
+ dsi_cinfo.regn = 19;
+ dsi_cinfo.regm = 150;
+ dsi_cinfo.regm3 = 4;
+ dsi_cinfo.regm4 = 4;
+ dsi_cinfo.use_dss2_fck = true;
+ dsi_cinfo.highfreq = 0;
+ dsi_calc_clock_rates(&dsi_cinfo);
+ }
+ r = dsi_pll_set_clock_div(lcd_channel_ix, &dsi_cinfo);
if (r)
return r;
dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(lcd_channel_ix, &dispc_cinfo);
if (r)
return r;
@@ -69,13 +79,15 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
return 0;
}
#else
-static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
+static int dpi_set_dispc_clk(int lcd_channel_ix, bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
{
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
int r;
+ if (cpu_is_omap44xx()) /*TODO Check this */
+ return 0;
r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
if (r)
return r;
@@ -84,7 +96,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
if (r)
return r;
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(lcd_channel_ix, &dispc_cinfo);
if (r)
return r;
@@ -103,20 +115,28 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
unsigned long fck;
unsigned long pck;
bool is_tft;
- int r = 0;
+ int r = 0, lcd_channel_ix = 0;
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ lcd_channel_ix = 1;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
- dssdev->panel.acb);
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ dispc_set_pol_freq(OMAP_DSS_CHANNEL_LCD2, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
+ else
+ dispc_set_pol_freq(OMAP_DSS_CHANNEL_LCD, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
+
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
+ r = dpi_set_dsi_clk(lcd_channel_ix, is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
#else
- r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
+ r = dpi_set_dispc_clk(lcd_channel_ix, is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
#endif
if (r)
@@ -132,8 +152,15 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
- dispc_set_lcd_timings(t);
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ dispc_set_lcd_timings(OMAP_DSS_CHANNEL_LCD2, t);
+ else
+ dispc_set_lcd_timings(OMAP_DSS_CHANNEL_LCD, t);
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+err1:
+ dsi_pll_uninit(lcd_channel_ix);
+#endif
err0:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
return r;
@@ -145,17 +172,51 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
- dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
- OMAP_DSS_LCD_DISPLAY_STN);
- dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
-
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
+ dispc_set_parallel_interface_mode(OMAP_DSS_CHANNEL_LCD2,
+ OMAP_DSS_PARALLELMODE_BYPASS);
+ dispc_set_lcd_display_type(OMAP_DSS_CHANNEL_LCD2,
+ is_tft ? OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
+ dispc_set_tft_data_lines(OMAP_DSS_CHANNEL_LCD2,
+ dssdev->phy.dpi.data_lines);
+
+ } else {
+ dispc_set_parallel_interface_mode(OMAP_DSS_CHANNEL_LCD,
+ OMAP_DSS_PARALLELMODE_BYPASS);
+ dispc_set_lcd_display_type(OMAP_DSS_CHANNEL_LCD,
+ is_tft ? OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
+ dispc_set_tft_data_lines(OMAP_DSS_CHANNEL_LCD,
+ dssdev->phy.dpi.data_lines);
+ }
return 0;
}
+/*This one needs to be to set the ovl info to dirty*/
+static void dpi_start_auto_update(struct omap_dss_device *dssdev)
+
+{
+ int i;
+ DSSDBG("starting auto update\n");
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(i);
+ if (ovl->manager == dssdev->manager)
+ ovl->info_dirty = true;
+ printk(KERN_ERR "ovl[%d]->manager = %s", i, ovl->manager->name);
+ }
+ dssdev->manager->apply(dssdev->manager);
+}
+
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
int r;
+ int lcd_channel_ix = 1;
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
+ printk("Lcd channel index 1");
+ lcd_channel_ix = 1;
+ } else
+ lcd_channel_ix = 0;
r = omap_dss_start_device(dssdev);
if (r) {
@@ -187,13 +248,16 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
+ if (cpu_is_omap44xx())
+ dpi_start_auto_update(dssdev);
+
dssdev->manager->enable(dssdev->manager);
return 0;
err4:
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- dsi_pll_uninit();
+ dsi_pll_uninit(lcd_channel_ix);
err3:
dss_clk_disable(DSS_CLK_FCK2);
#endif
@@ -210,11 +274,16 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
+ int lcd_channel_ix = 0;
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ lcd_channel_ix = 1;
+
dssdev->manager->disable(dssdev->manager);
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dsi_pll_uninit();
+ dsi_pll_uninit(lcd_channel_ix);
dss_clk_disable(DSS_CLK_FCK2);
#endif
@@ -234,7 +303,10 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
dpi_set_mode(dssdev);
- dispc_go(OMAP_DSS_CHANNEL_LCD);
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ dispc_go(OMAP_DSS_CHANNEL_LCD2);
+ else
+ dispc_go(OMAP_DSS_CHANNEL_LCD);
}
}
EXPORT_SYMBOL(dpi_set_timings);
@@ -243,11 +315,14 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
bool is_tft;
- int r;
+ int r = 0, lcd_channel_ix = 0;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2)
+ lcd_channel_ix = 1;
+
if (!dispc_lcd_timings_ok(timings))
return -EINVAL;
@@ -260,7 +335,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
{
struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
- r = dsi_pll_calc_clock_div_pck(is_tft,
+ r = dsi_pll_calc_clock_div_pck(lcd_channel_ix, is_tft,
timings->pixel_clock * 1000,
&dsi_cinfo, &dispc_cinfo);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 3af207b2bde3..2602a6617e2f 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -42,7 +42,13 @@
/*#define VERBOSE_IRQ*/
#define DSI_CATCH_MISSING_TE
+#ifndef CONFIG_ARCH_OMAP4
#define DSI_BASE 0x4804FC00
+#else
+#define DSI_BASE 0x58004000
+#define DSI2_BASE 0x58005000
+
+#endif
struct dsi_reg { u16 idx; };
@@ -92,6 +98,13 @@ struct dsi_reg { u16 idx; };
#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
+/* DSI Rev 3.0 Registers */
+
+#define DSI_DSIPHY_CFG8 DSI_REG(0x200 + 0x0020)
+#define DSI_DSIPHY_CFG9 DSI_REG(0x200 + 0x0024)
+#define DSI_DSIPHY_CFG12 DSI_REG(0x200 + 0x0030)
+#define DSI_DSIPHY_CFG14 DSI_REG(0x200 + 0x0038)
+
/* DSI_PLL_CTRL_SCP */
#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
@@ -100,11 +113,11 @@ struct dsi_reg { u16 idx; };
#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
-#define REG_GET(idx, start, end) \
- FLD_GET(dsi_read_reg(idx), start, end)
+#define REG_GET(no, idx, start, end) \
+ FLD_GET(dsi_read_reg(no, idx), start, end)
-#define REG_FLD_MOD(idx, val, start, end) \
- dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
+#define REG_FLD_MOD(no, idx, val, start, end) \
+ dsi_write_reg(no, idx, FLD_MOD(dsi_read_reg(no, idx), val, start, end))
/* Global interrupts */
#define DSI_IRQ_VC0 (1 << 0)
@@ -212,7 +225,7 @@ struct dsi_irq_stats {
unsigned cio_irqs[32];
};
-static struct
+static struct dsi_struct
{
void __iomem *base;
@@ -224,6 +237,7 @@ static struct
enum dsi_vc_mode mode;
struct omap_dss_device *dssdev;
enum fifo_size fifo_size;
+ int dest_per;
} vc[4];
struct mutex lock;
@@ -237,7 +251,7 @@ static struct
struct dsi_update_region update_region;
bool te_enabled;
-
+ bool use_ext_te;
struct work_struct framedone_work;
void (*framedone_callback)(int, void *);
void *framedone_data;
@@ -265,21 +279,29 @@ static struct
spinlock_t irq_stats_lock;
struct dsi_irq_stats irq_stats;
#endif
-} dsi;
+} dsi1, dsi2;
#ifdef DEBUG
static unsigned int dsi_perf;
module_param_named(dsi_perf, dsi_perf, bool, 0644);
#endif
-static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
+static inline void dsi_write_reg(enum omap_dsi_index ix,
+ const struct dsi_reg idx, u32 val)
{
- __raw_writel(val, dsi.base + idx.idx);
+ if (ix == DSI1)
+ __raw_writel(val, dsi1.base + idx.idx);
+ else
+ __raw_writel(val, dsi2.base + idx.idx);
}
-static inline u32 dsi_read_reg(const struct dsi_reg idx)
+static inline u32 dsi_read_reg(enum omap_dsi_index ix,
+ const struct dsi_reg idx)
{
- return __raw_readl(dsi.base + idx.idx);
+ if (ix == DSI1)
+ return __raw_readl(dsi1.base + idx.idx);
+ else
+ return __raw_readl(dsi2.base + idx.idx);
}
@@ -291,29 +313,39 @@ void dsi_restore_context(void)
{
}
-void dsi_bus_lock(void)
+void dsi_bus_lock(enum omap_dsi_index ix)
{
- down(&dsi.bus_lock);
+ if (ix == DSI1)
+ down(&dsi1.bus_lock);
+ else
+ down(&dsi2.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_lock);
-void dsi_bus_unlock(void)
+void dsi_bus_unlock(enum omap_dsi_index ix)
{
- up(&dsi.bus_lock);
+ if (ix == DSI1)
+ up(&dsi1.bus_lock);
+ else
+ up(&dsi2.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_unlock);
-static bool dsi_bus_is_locked(void)
+static bool dsi_bus_is_locked(enum omap_dsi_index ix)
{
- return dsi.bus_lock.count == 0;
+ if (ix == DSI1)
+ return dsi1.bus_lock.count == 0;
+ else
+ return dsi2.bus_lock.count == 0;
}
-static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
+static inline int wait_for_bit_change(enum omap_dsi_index ix,
+ const struct dsi_reg idx, int bitnum,
int value)
{
int t = 100000;
- while (REG_GET(idx, bitnum, bitnum) != value) {
+ while (REG_GET(ix, idx, bitnum, bitnum) != value) {
if (--t == 0)
return !value;
}
@@ -322,42 +354,49 @@ static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
}
#ifdef DEBUG
-static void dsi_perf_mark_setup(void)
+static void dsi_perf_mark_setup(enum omap_dsi_index ix)
{
- dsi.perf_setup_time = ktime_get();
+ struct dsi_struct *p_dsi;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ p_dsi->perf_setup_time = ktime_get();
}
-static void dsi_perf_mark_start(void)
+static void dsi_perf_mark_start(enum omap_dsi_index ix)
{
- dsi.perf_start_time = ktime_get();
+ struct dsi_struct *p_dsi;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ p_dsi->perf_start_time = ktime_get();
}
-static void dsi_perf_show(const char *name)
+static void dsi_perf_show(enum omap_dsi_index ix,
+ const char *name)
{
ktime_t t, setup_time, trans_time;
u32 total_bytes;
u32 setup_us, trans_us, total_us;
+ struct dsi_struct *p_dsi;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
if (!dsi_perf)
return;
t = ktime_get();
- setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
+ setup_time = ktime_sub(p_dsi->perf_start_time, p_dsi->perf_setup_time);
setup_us = (u32)ktime_to_us(setup_time);
if (setup_us == 0)
setup_us = 1;
- trans_time = ktime_sub(t, dsi.perf_start_time);
+ trans_time = ktime_sub(t, p_dsi->perf_start_time);
trans_us = (u32)ktime_to_us(trans_time);
if (trans_us == 0)
trans_us = 1;
total_us = setup_us + trans_us;
- total_bytes = dsi.update_region.w *
- dsi.update_region.h *
- dsi.update_region.device->ctrl.pixel_size / 8;
+ total_bytes = p_dsi->update_region.w *
+ p_dsi->update_region.h *
+ p_dsi->update_region.device->ctrl.pixel_size / 8;
printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
"%u bytes, %u kbytes/sec\n",
@@ -370,9 +409,9 @@ static void dsi_perf_show(const char *name)
total_bytes * 1000 / total_us);
}
#else
-#define dsi_perf_mark_setup()
-#define dsi_perf_mark_start()
-#define dsi_perf_show(x)
+#define dsi_perf_mark_setup(x)
+#define dsi_perf_mark_start(x)
+#define dsi_perf_show(x, y)
#endif
static void print_irq_status(u32 status)
@@ -470,47 +509,56 @@ static void print_irq_status_cio(u32 status)
static int debug_irq;
-/* called from dss */
-void dsi_irq_handler(void)
+/* called from dss in OMAP3, in OMAP4 there is a dedicated
+* interrupt line for DSI */
+irqreturn_t dsi_irq_handler(int irq, void *arg)
+
{
u32 irqstatus, vcstatus, ciostatus;
int i;
+ enum omap_dsi_index ix = DSI1;
+ struct dsi_struct *p_dsi;
+
+ if (cpu_is_omap44xx() && irq == OMAP44XX_IRQ_DSS_DSI2)
+ ix = DSI2;
- irqstatus = dsi_read_reg(DSI_IRQSTATUS);
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ irqstatus = dsi_read_reg(ix, DSI_IRQSTATUS);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- spin_lock(&dsi.irq_stats_lock);
- dsi.irq_stats.irq_count++;
- dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+ spin_lock(&p_dsi->irq_stats_lock);
+ p_dsi->irq_stats.irq_count++;
+ dss_collect_irq_stats(irqstatus, p_dsi->irq_stats.dsi_irqs);
#endif
if (irqstatus & DSI_IRQ_ERROR_MASK) {
DSSERR("DSI error, irqstatus %x\n", irqstatus);
print_irq_status(irqstatus);
- spin_lock(&dsi.errors_lock);
- dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
- spin_unlock(&dsi.errors_lock);
+ spin_lock(&p_dsi->errors_lock);
+ p_dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
+ spin_unlock(&p_dsi->errors_lock);
} else if (debug_irq) {
print_irq_status(irqstatus);
}
#ifdef DSI_CATCH_MISSING_TE
if (irqstatus & DSI_IRQ_TE_TRIGGER)
- del_timer(&dsi.te_timer);
+ del_timer(&p_dsi->te_timer);
#endif
for (i = 0; i < 4; ++i) {
if ((irqstatus & (1<<i)) == 0)
continue;
- vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+ vcstatus = dsi_read_reg(ix, DSI_VC_IRQSTATUS(i));
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
+ dss_collect_irq_stats(vcstatus, p_dsi->irq_stats.vc_irqs[i]);
#endif
if (vcstatus & DSI_VC_IRQ_BTA)
- complete(&dsi.bta_completion);
+ complete(&p_dsi->bta_completion);
if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
@@ -520,106 +568,110 @@ void dsi_irq_handler(void)
print_irq_status_vc(i, vcstatus);
}
- dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
+ dsi_write_reg(ix, DSI_VC_IRQSTATUS(i), vcstatus);
/* flush posted write */
- dsi_read_reg(DSI_VC_IRQSTATUS(i));
+ dsi_read_reg(ix, DSI_VC_IRQSTATUS(i));
}
if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
- ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+ ciostatus = dsi_read_reg(ix, DSI_COMPLEXIO_IRQ_STATUS);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+ dss_collect_irq_stats(ciostatus, p_dsi->irq_stats.cio_irqs);
#endif
- dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
+ dsi_write_reg(ix, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
/* flush posted write */
- dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+ dsi_read_reg(ix, DSI_COMPLEXIO_IRQ_STATUS);
DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
print_irq_status_cio(ciostatus);
}
- dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+ dsi_write_reg(ix, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
/* flush posted write */
- dsi_read_reg(DSI_IRQSTATUS);
+ dsi_read_reg(ix, DSI_IRQSTATUS);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- spin_unlock(&dsi.irq_stats_lock);
+ spin_unlock(&p_dsi->irq_stats_lock);
#endif
+ return IRQ_HANDLED;
}
-
-static void _dsi_initialize_irq(void)
+static void _dsi_initialize_irq(enum omap_dsi_index ix)
{
u32 l;
int i;
/* disable all interrupts */
- dsi_write_reg(DSI_IRQENABLE, 0);
+ dsi_write_reg(ix, DSI_IRQENABLE, 0);
for (i = 0; i < 4; ++i)
- dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
- dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
+ dsi_write_reg(ix, DSI_VC_IRQENABLE(i), 0);
+ dsi_write_reg(ix, DSI_COMPLEXIO_IRQ_ENABLE, 0);
/* clear interrupt status */
- l = dsi_read_reg(DSI_IRQSTATUS);
- dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
+ l = dsi_read_reg(ix, DSI_IRQSTATUS);
+ dsi_write_reg(ix, DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
for (i = 0; i < 4; ++i) {
- l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
- dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
+ l = dsi_read_reg(ix, DSI_VC_IRQSTATUS(i));
+ dsi_write_reg(ix, DSI_VC_IRQSTATUS(i), l);
}
- l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
- dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
+ l = dsi_read_reg(ix, DSI_COMPLEXIO_IRQ_STATUS);
+ dsi_write_reg(ix, DSI_COMPLEXIO_IRQ_STATUS, l);
/* enable error irqs */
l = DSI_IRQ_ERROR_MASK;
#ifdef DSI_CATCH_MISSING_TE
l |= DSI_IRQ_TE_TRIGGER;
#endif
- dsi_write_reg(DSI_IRQENABLE, l);
+ dsi_write_reg(ix, DSI_IRQENABLE, l);
l = DSI_VC_IRQ_ERROR_MASK;
for (i = 0; i < 4; ++i)
- dsi_write_reg(DSI_VC_IRQENABLE(i), l);
+ dsi_write_reg(ix, DSI_VC_IRQENABLE(i), l);
/* XXX zonda responds incorrectly, causing control error:
Exit from LP-ESC mode to LP11 uses wrong transition states on the
data lines LP0 and LN0. */
- dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
+ dsi_write_reg(ix, DSI_COMPLEXIO_IRQ_ENABLE,
-1 & (~DSI_CIO_IRQ_ERRCONTROL2));
}
-static u32 dsi_get_errors(void)
+static u32 dsi_get_errors(enum omap_dsi_index ix)
{
unsigned long flags;
u32 e;
- spin_lock_irqsave(&dsi.errors_lock, flags);
- e = dsi.errors;
- dsi.errors = 0;
- spin_unlock_irqrestore(&dsi.errors_lock, flags);
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ spin_lock_irqsave(&p_dsi->errors_lock, flags);
+ e = p_dsi->errors;
+ p_dsi->errors = 0;
+ spin_unlock_irqrestore(&p_dsi->errors_lock, flags);
return e;
}
-static void dsi_vc_enable_bta_irq(int channel)
+static void dsi_vc_enable_bta_irq(enum omap_dsi_index ix,
+ int channel)
{
u32 l;
- dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
+ dsi_write_reg(ix, DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
- l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
+ l = dsi_read_reg(ix, DSI_VC_IRQENABLE(channel));
l |= DSI_VC_IRQ_BTA;
- dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+ dsi_write_reg(ix, DSI_VC_IRQENABLE(channel), l);
}
-static void dsi_vc_disable_bta_irq(int channel)
+static void dsi_vc_disable_bta_irq(enum omap_dsi_index ix,
+ int channel)
{
u32 l;
- l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
+ l = dsi_read_reg(ix, DSI_VC_IRQENABLE(channel));
l &= ~DSI_VC_IRQ_BTA;
- dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+ dsi_write_reg(ix, DSI_VC_IRQENABLE(channel), l);
}
/* DSI func clock. this could also be DSI2_PLL_FCLK */
@@ -632,21 +684,24 @@ static inline void enable_clocks(bool enable)
}
/* source clock for DSI PLL. this could also be PCLKFREE */
-static inline void dsi_enable_pll_clock(bool enable)
+static inline void dsi_enable_pll_clock(enum omap_dsi_index ix,
+ bool enable)
{
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
if (enable)
dss_clk_enable(DSS_CLK_FCK2);
else
dss_clk_disable(DSS_CLK_FCK2);
- if (enable && dsi.pll_locked) {
- if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
+ if (enable && p_dsi->pll_locked) {
+ if (wait_for_bit_change(ix, DSI_PLL_STATUS, 1, 1) != 1)
DSSERR("cannot lock PLL when enabling clocks\n");
}
}
#ifdef DEBUG
-static void _dsi_print_reset_status(void)
+static void _dsi_print_reset_status(enum omap_dsi_index ix)
{
u32 l;
@@ -656,17 +711,17 @@ static void _dsi_print_reset_status(void)
/* A dummy read using the SCP interface to any DSIPHY register is
* required after DSIPHY reset to complete the reset of the DSI complex
* I/O. */
- l = dsi_read_reg(DSI_DSIPHY_CFG5);
+ l = dsi_read_reg(ix, DSI_DSIPHY_CFG5);
printk(KERN_DEBUG "DSI resets: ");
- l = dsi_read_reg(DSI_PLL_STATUS);
+ l = dsi_read_reg(ix, DSI_PLL_STATUS);
printk("PLL (%d) ", FLD_GET(l, 0, 0));
- l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+ l = dsi_read_reg(ix, DSI_COMPLEXIO_CFG1);
printk("CIO (%d) ", FLD_GET(l, 29, 29));
- l = dsi_read_reg(DSI_DSIPHY_CFG5);
+ l = dsi_read_reg(ix, DSI_DSIPHY_CFG5);
printk("PHY (%x, %d, %d, %d)\n",
FLD_GET(l, 28, 26),
FLD_GET(l, 29, 29),
@@ -674,17 +729,18 @@ static void _dsi_print_reset_status(void)
FLD_GET(l, 31, 31));
}
#else
-#define _dsi_print_reset_status()
+#define _dsi_print_reset_status(ix)
#endif
-static inline int dsi_if_enable(bool enable)
+static inline int dsi_if_enable(enum omap_dsi_index ix,
+ bool enable)
{
DSSDBG("dsi_if_enable(%d)\n", enable);
enable = enable ? 1 : 0;
- REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
+ REG_FLD_MOD(ix, DSI_CTRL, enable, 0, 0); /* IF_EN */
- if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
+ if (wait_for_bit_change(ix, DSI_CTRL, 0, enable) != enable) {
DSSERR("Failed to set dsi_if_enable to %d\n", enable);
return -EIO;
}
@@ -692,22 +748,25 @@ static inline int dsi_if_enable(bool enable)
return 0;
}
-unsigned long dsi_get_dsi1_pll_rate(void)
+unsigned long dsi_get_dsi1_pll_rate(enum omap_dsi_index ix)
{
- return dsi.current_cinfo.dsi1_pll_fclk;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ return p_dsi->current_cinfo.dsi1_pll_fclk;
}
-static unsigned long dsi_get_dsi2_pll_rate(void)
+static unsigned long dsi_get_dsi2_pll_rate(enum omap_dsi_index ix)
{
- return dsi.current_cinfo.dsi2_pll_fclk;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ return p_dsi->current_cinfo.dsi2_pll_fclk;
}
-static unsigned long dsi_get_txbyteclkhs(void)
+static unsigned long dsi_get_txbyteclkhs(enum omap_dsi_index ix)
{
- return dsi.current_cinfo.clkin4ddr / 16;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ return p_dsi->current_cinfo.clkin4ddr / 16;
}
-static unsigned long dsi_fclk_rate(void)
+static unsigned long dsi_fclk_rate(enum omap_dsi_index ix)
{
unsigned long r;
@@ -716,7 +775,7 @@ static unsigned long dsi_fclk_rate(void)
r = dss_clk_get_rate(DSS_CLK_FCK1);
} else {
/* DSI FCLK source is DSI2_PLL_FCLK */
- r = dsi_get_dsi2_pll_rate();
+ r = dsi_get_dsi2_pll_rate(ix);
}
return r;
@@ -727,23 +786,28 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
unsigned long dsi_fclk;
unsigned lp_clk_div;
unsigned long lp_clk;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
return -EINVAL;
- dsi_fclk = dsi_fclk_rate();
+ dsi_fclk = dsi_fclk_rate(ix);
lp_clk = dsi_fclk / 2 / lp_clk_div;
DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
- dsi.current_cinfo.lp_clk = lp_clk;
- dsi.current_cinfo.lp_clk_div = lp_clk_div;
+ p_dsi->current_cinfo.lp_clk = lp_clk;
+ p_dsi->current_cinfo.lp_clk_div = lp_clk_div;
- REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_CLK_DIVISOR */
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_CLK_DIVISOR */
- REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
21, 21); /* LP_RX_SYNCHRO_ENABLE */
return 0;
@@ -757,14 +821,15 @@ enum dsi_pll_power_state {
DSI_PLL_POWER_ON_DIV = 0x3,
};
-static int dsi_pll_power(enum dsi_pll_power_state state)
+static int dsi_pll_power(enum omap_dsi_index ix,
+ enum dsi_pll_power_state state)
{
int t = 0;
- REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
/* PLL_PWR_STATUS */
- while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
+ while (FLD_GET(dsi_read_reg(ix, DSI_CLK_CTRL), 29, 28) != state) {
if (++t > 1000) {
DSSERR("Failed to set DSI PLL power mode to %d\n",
state);
@@ -777,7 +842,7 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
}
/* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
+int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
{
if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
return -EINVAL;
@@ -793,11 +858,12 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
if (cinfo->use_dss2_fck) {
cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
+ cinfo->clkin = 38400000;
/* XXX it is unclear if highfreq should be used
* with DSS2_FCK source also */
cinfo->highfreq = 0;
} else {
- cinfo->clkin = dispc_pclk_rate();
+ cinfo->clkin = dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD);
if (cinfo->clkin < 32000000)
cinfo->highfreq = 0;
@@ -828,7 +894,8 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
return 0;
}
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
+int dsi_pll_calc_clock_div_pck(enum omap_dsi_index ix,
+ bool is_tft, unsigned long req_pck,
struct dsi_clock_info *dsi_cinfo,
struct dispc_clock_info *dispc_cinfo)
{
@@ -837,13 +904,14 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
int min_fck_per_pck;
int match = 0;
unsigned long dss_clk_fck2;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
- if (req_pck == dsi.cache_req_pck &&
- dsi.cache_cinfo.clkin == dss_clk_fck2) {
+ if (req_pck == p_dsi->cache_req_pck &&
+ p_dsi->cache_cinfo.clkin == dss_clk_fck2) {
DSSDBG("DSI clock info found from cache\n");
- *dsi_cinfo = dsi.cache_cinfo;
+ *dsi_cinfo = p_dsi->cache_cinfo;
dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
dispc_cinfo);
return 0;
@@ -954,30 +1022,32 @@ found:
if (dispc_cinfo)
*dispc_cinfo = best_dispc;
- dsi.cache_req_pck = req_pck;
- dsi.cache_clk_freq = 0;
- dsi.cache_cinfo = best;
+ p_dsi->cache_req_pck = req_pck;
+ p_dsi->cache_clk_freq = 0;
+ p_dsi->cache_cinfo = best;
return 0;
}
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
+int dsi_pll_set_clock_div(enum omap_dsi_index ix,
+ struct dsi_clock_info *cinfo)
{
int r = 0;
u32 l;
- int f;
+ int f = 0;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
DSSDBGF();
- dsi.current_cinfo.fint = cinfo->fint;
- dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
- dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
- dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
+ p_dsi->current_cinfo.fint = cinfo->fint;
+ p_dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
+ p_dsi->current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
+ p_dsi->current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
- dsi.current_cinfo.regn = cinfo->regn;
- dsi.current_cinfo.regm = cinfo->regm;
- dsi.current_cinfo.regm3 = cinfo->regm3;
- dsi.current_cinfo.regm4 = cinfo->regm4;
+ p_dsi->current_cinfo.regn = cinfo->regn;
+ p_dsi->current_cinfo.regm = cinfo->regm;
+ p_dsi->current_cinfo.regm3 = cinfo->regm3;
+ p_dsi->current_cinfo.regm4 = cinfo->regm4;
DSSDBG("DSI Fint %ld\n", cinfo->fint);
@@ -1004,32 +1074,39 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
cinfo->regm4, cinfo->dsi2_pll_fclk);
- REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
+ REG_FLD_MOD(ix, DSI_PLL_CONTROL, 0,
+ 0, 0); /* DSI_PLL_AUTOMODE = manual */
- l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
+ l = dsi_read_reg(ix, DSI_PLL_CONFIGURATION1);
l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
- l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
- l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
+ l = FLD_MOD(l, cinfo->regn - 1, (cpu_is_omap44xx()) ? 8 : 7,
+ 1); /* DSI_PLL_REGN */
+ l = FLD_MOD(l, cinfo->regm, (cpu_is_omap44xx()) ? 20 : 18,
+ (cpu_is_omap44xx()) ? 9 : 8); /* DSI_PLL_REGM */
l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
- 22, 19); /* DSI_CLOCK_DIV */
+ (cpu_is_omap44xx()) ? 25 : 22,
+ (cpu_is_omap44xx()) ? 21 : 19); /* DSI_CLOCK_DIV */
l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
- 26, 23); /* DSIPROTO_CLOCK_DIV */
- dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
+ (cpu_is_omap44xx()) ? 30 : 26,
+ (cpu_is_omap44xx()) ? 26 : 23); /* DSIPROTO_CLOCK_DIV */
+ dsi_write_reg(ix, DSI_PLL_CONFIGURATION1, l);
BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
- if (cinfo->fint < 1000000)
- f = 0x3;
- else if (cinfo->fint < 1250000)
- f = 0x4;
- else if (cinfo->fint < 1500000)
- f = 0x5;
- else if (cinfo->fint < 1750000)
- f = 0x6;
- else
- f = 0x7;
-
- l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
- l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
+ if (!cpu_is_omap44xx()) {
+ if (cinfo->fint < 1000000)
+ f = 0x3;
+ else if (cinfo->fint < 1250000)
+ f = 0x4;
+ else if (cinfo->fint < 1500000)
+ f = 0x5;
+ else if (cinfo->fint < 1750000)
+ f = 0x6;
+ else
+ f = 0x7;
+ }
+ l = dsi_read_reg(ix, DSI_PLL_CONFIGURATION2);
+ if (!cpu_is_omap44xx())
+ l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
11, 11); /* DSI_PLL_CLKSEL */
l = FLD_MOD(l, cinfo->highfreq,
@@ -1037,29 +1114,32 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
- dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+ if (cpu_is_omap44xx())
+ l = FLD_MOD(l, 3, 22, 21); /* DSI_REF_SEL */
+ dsi_write_reg(ix, DSI_PLL_CONFIGURATION2, l);
- REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
+ REG_FLD_MOD(ix, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
- if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
+ if (wait_for_bit_change(ix, DSI_PLL_GO, 0, 0) != 0) {
DSSERR("dsi pll go bit not going down.\n");
r = -EIO;
goto err;
}
- if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
+ if (wait_for_bit_change(ix, DSI_PLL_STATUS, 1, 1) != 1) {
DSSERR("cannot lock PLL\n");
r = -EIO;
goto err;
}
- dsi.pll_locked = 1;
+ p_dsi->pll_locked = 1;
- l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
+ l = dsi_read_reg(ix, DSI_PLL_CONFIGURATION2);
l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
- l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
+ if (!cpu_is_omap44xx())
+ l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
@@ -1070,7 +1150,11 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
- dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+ if (cpu_is_omap44xx()) {
+ l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
+ l = FLD_MOD(l, 0, 26, 26); /* M7_CLOCK_PWDN */
+ }
+ dsi_write_reg(ix, DSI_PLL_CONFIGURATION2, l);
DSSDBG("PLL config done\n");
err:
@@ -1082,20 +1166,30 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
{
int r = 0;
enum dsi_pll_power_state pwstate;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
DSSDBG("PLL init\n");
+ /* The SCPClk is required for PLL registers in OMAP4 */
+ if (cpu_is_omap44xx())
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, 1, 14, 14);
+
enable_clocks(1);
- dsi_enable_pll_clock(1);
+ dsi_enable_pll_clock(ix, 1);
- r = regulator_enable(dsi.vdds_dsi_reg);
- if (r)
- goto err0;
+ if (!cpu_is_omap44xx()) {
+ r = regulator_enable(dsi1.vdds_dsi_reg);
+ if (r)
+ goto err0;
+ }
/* XXX PLL does not come out of reset without this... */
- dispc_pck_free_enable(1);
+ if (!cpu_is_omap44xx())
+ dispc_pck_free_enable(1);
- if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
+ if (wait_for_bit_change(ix, DSI_PLL_STATUS, 0, 1) != 1) {
DSSERR("PLL not coming out of reset.\n");
r = -ENODEV;
goto err1;
@@ -1103,7 +1197,8 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
/* XXX ... but if left on, we get problems when planes do not
* fill the whole display. No idea about this */
- dispc_pck_free_enable(0);
+ if (!cpu_is_omap44xx())
+ dispc_pck_free_enable(0);
if (enable_hsclk && enable_hsdiv)
pwstate = DSI_PLL_POWER_ON_ALL;
@@ -1114,7 +1209,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
else
pwstate = DSI_PLL_POWER_OFF;
- r = dsi_pll_power(pwstate);
+ r = dsi_pll_power(ix, pwstate);
if (r)
goto err1;
@@ -1123,32 +1218,37 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
return 0;
err1:
- regulator_disable(dsi.vdds_dsi_reg);
+ if (!cpu_is_omap44xx())
+ regulator_disable(dsi1.vdds_dsi_reg);
err0:
enable_clocks(0);
- dsi_enable_pll_clock(0);
+ dsi_enable_pll_clock(ix, 0);
return r;
}
-void dsi_pll_uninit(void)
+void dsi_pll_uninit(enum omap_dsi_index ix)
{
+ struct dsi_struct *p_dsi;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
enable_clocks(0);
- dsi_enable_pll_clock(0);
+ dsi_enable_pll_clock(ix, 0);
- dsi.pll_locked = 0;
- dsi_pll_power(DSI_PLL_POWER_OFF);
- regulator_disable(dsi.vdds_dsi_reg);
+ p_dsi->pll_locked = 0;
+ dsi_pll_power(ix, DSI_PLL_POWER_OFF);
+ if (!cpu_is_omap44xx())
+ regulator_disable(dsi1.vdds_dsi_reg);
DSSDBG("PLL uninit done\n");
}
-void dsi_dump_clocks(struct seq_file *s)
+void dsi_dump_clocks(enum omap_dsi_index ix, struct seq_file *s)
{
int clksel;
- struct dsi_clock_info *cinfo = &dsi.current_cinfo;
-
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ struct dsi_clock_info *cinfo = &p_dsi->current_cinfo;
enable_clocks(1);
- clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
+ clksel = REG_GET(ix, DSI_PLL_CONFIGURATION2, 11, 11);
seq_printf(s, "- DSI PLL -\n");
@@ -1179,36 +1279,37 @@ void dsi_dump_clocks(struct seq_file *s)
dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
"dss1_alwon_fclk" : "dsi2_pll_fclk");
- seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
+ seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(ix));
seq_printf(s, "DDR_CLK\t\t%lu\n",
cinfo->clkin4ddr / 4);
- seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
+ seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(ix));
seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
seq_printf(s, "VP_CLK\t\t%lu\n"
"VP_PCLK\t\t%lu\n",
- dispc_lclk_rate(),
- dispc_pclk_rate());
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
enable_clocks(0);
}
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-void dsi_dump_irqs(struct seq_file *s)
+void dsi_dump_irqs(enum omap_dsi_index ix, struct seq_file *s)
{
unsigned long flags;
struct dsi_irq_stats stats;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- spin_lock_irqsave(&dsi.irq_stats_lock, flags);
+ spin_lock_irqsave(&p_dsi->irq_stats_lock, flags);
- stats = dsi.irq_stats;
- memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
- dsi.irq_stats.last_reset = jiffies;
+ stats = p_dsi->irq_stats;
+ memset(&p_dsi->irq_stats, 0, sizeof(p_dsi->irq_stats));
+ p_dsi->irq_stats.last_reset = jiffies;
- spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
+ spin_unlock_irqrestore(&p_dsi->irq_stats_lock, flags);
seq_printf(s, "period %u ms\n",
jiffies_to_msecs(jiffies - stats.last_reset));
@@ -1285,81 +1386,81 @@ void dsi_dump_irqs(struct seq_file *s)
}
#endif
-void dsi_dump_regs(struct seq_file *s)
+void dsi_dump_regs(enum omap_dsi_index ix, struct seq_file *s)
{
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
+#define DUMPREG(ix, r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(ix, r))
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
- DUMPREG(DSI_REVISION);
- DUMPREG(DSI_SYSCONFIG);
- DUMPREG(DSI_SYSSTATUS);
- DUMPREG(DSI_IRQSTATUS);
- DUMPREG(DSI_IRQENABLE);
- DUMPREG(DSI_CTRL);
- DUMPREG(DSI_COMPLEXIO_CFG1);
- DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
- DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
- DUMPREG(DSI_CLK_CTRL);
- DUMPREG(DSI_TIMING1);
- DUMPREG(DSI_TIMING2);
- DUMPREG(DSI_VM_TIMING1);
- DUMPREG(DSI_VM_TIMING2);
- DUMPREG(DSI_VM_TIMING3);
- DUMPREG(DSI_CLK_TIMING);
- DUMPREG(DSI_TX_FIFO_VC_SIZE);
- DUMPREG(DSI_RX_FIFO_VC_SIZE);
- DUMPREG(DSI_COMPLEXIO_CFG2);
- DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
- DUMPREG(DSI_VM_TIMING4);
- DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
- DUMPREG(DSI_VM_TIMING5);
- DUMPREG(DSI_VM_TIMING6);
- DUMPREG(DSI_VM_TIMING7);
- DUMPREG(DSI_STOPCLK_TIMING);
-
- DUMPREG(DSI_VC_CTRL(0));
- DUMPREG(DSI_VC_TE(0));
- DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
- DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
- DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
- DUMPREG(DSI_VC_IRQSTATUS(0));
- DUMPREG(DSI_VC_IRQENABLE(0));
-
- DUMPREG(DSI_VC_CTRL(1));
- DUMPREG(DSI_VC_TE(1));
- DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
- DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
- DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
- DUMPREG(DSI_VC_IRQSTATUS(1));
- DUMPREG(DSI_VC_IRQENABLE(1));
-
- DUMPREG(DSI_VC_CTRL(2));
- DUMPREG(DSI_VC_TE(2));
- DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
- DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
- DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
- DUMPREG(DSI_VC_IRQSTATUS(2));
- DUMPREG(DSI_VC_IRQENABLE(2));
-
- DUMPREG(DSI_VC_CTRL(3));
- DUMPREG(DSI_VC_TE(3));
- DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
- DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
- DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
- DUMPREG(DSI_VC_IRQSTATUS(3));
- DUMPREG(DSI_VC_IRQENABLE(3));
-
- DUMPREG(DSI_DSIPHY_CFG0);
- DUMPREG(DSI_DSIPHY_CFG1);
- DUMPREG(DSI_DSIPHY_CFG2);
- DUMPREG(DSI_DSIPHY_CFG5);
-
- DUMPREG(DSI_PLL_CONTROL);
- DUMPREG(DSI_PLL_STATUS);
- DUMPREG(DSI_PLL_GO);
- DUMPREG(DSI_PLL_CONFIGURATION1);
- DUMPREG(DSI_PLL_CONFIGURATION2);
+ DUMPREG(ix, DSI_REVISION);
+ DUMPREG(ix, DSI_SYSCONFIG);
+ DUMPREG(ix, DSI_SYSSTATUS);
+ DUMPREG(ix, DSI_IRQSTATUS);
+ DUMPREG(ix, DSI_IRQENABLE);
+ DUMPREG(ix, DSI_CTRL);
+ DUMPREG(ix, DSI_COMPLEXIO_CFG1);
+ DUMPREG(ix, DSI_COMPLEXIO_IRQ_STATUS);
+ DUMPREG(ix, DSI_COMPLEXIO_IRQ_ENABLE);
+ DUMPREG(ix, DSI_CLK_CTRL);
+ DUMPREG(ix, DSI_TIMING1);
+ DUMPREG(ix, DSI_TIMING2);
+ DUMPREG(ix, DSI_VM_TIMING1);
+ DUMPREG(ix, DSI_VM_TIMING2);
+ DUMPREG(ix, DSI_VM_TIMING3);
+ DUMPREG(ix, DSI_CLK_TIMING);
+ DUMPREG(ix, DSI_TX_FIFO_VC_SIZE);
+ DUMPREG(ix, DSI_RX_FIFO_VC_SIZE);
+ DUMPREG(ix, DSI_COMPLEXIO_CFG2);
+ DUMPREG(ix, DSI_RX_FIFO_VC_FULLNESS);
+ DUMPREG(ix, DSI_VM_TIMING4);
+ DUMPREG(ix, DSI_TX_FIFO_VC_EMPTINESS);
+ DUMPREG(ix, DSI_VM_TIMING5);
+ DUMPREG(ix, DSI_VM_TIMING6);
+ DUMPREG(ix, DSI_VM_TIMING7);
+ DUMPREG(ix, DSI_STOPCLK_TIMING);
+
+ DUMPREG(ix, DSI_VC_CTRL(0));
+ DUMPREG(ix, DSI_VC_TE(0));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_HEADER(0));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_PAYLOAD(0));
+ DUMPREG(ix, DSI_VC_SHORT_PACKET_HEADER(0));
+ DUMPREG(ix, DSI_VC_IRQSTATUS(0));
+ DUMPREG(ix, DSI_VC_IRQENABLE(0));
+
+ DUMPREG(ix, DSI_VC_CTRL(1));
+ DUMPREG(ix, DSI_VC_TE(1));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_HEADER(1));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_PAYLOAD(1));
+ DUMPREG(ix, DSI_VC_SHORT_PACKET_HEADER(1));
+ DUMPREG(ix, DSI_VC_IRQSTATUS(1));
+ DUMPREG(ix, DSI_VC_IRQENABLE(1));
+
+ DUMPREG(ix, DSI_VC_CTRL(2));
+ DUMPREG(ix, DSI_VC_TE(2));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_HEADER(2));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_PAYLOAD(2));
+ DUMPREG(ix, DSI_VC_SHORT_PACKET_HEADER(2));
+ DUMPREG(ix, DSI_VC_IRQSTATUS(2));
+ DUMPREG(ix, DSI_VC_IRQENABLE(2));
+
+ DUMPREG(ix, DSI_VC_CTRL(3));
+ DUMPREG(ix, DSI_VC_TE(3));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_HEADER(3));
+ DUMPREG(ix, DSI_VC_LONG_PACKET_PAYLOAD(3));
+ DUMPREG(ix, DSI_VC_SHORT_PACKET_HEADER(3));
+ DUMPREG(ix, DSI_VC_IRQSTATUS(3));
+ DUMPREG(ix, DSI_VC_IRQENABLE(3));
+
+ DUMPREG(ix, DSI_DSIPHY_CFG0);
+ DUMPREG(ix, DSI_DSIPHY_CFG1);
+ DUMPREG(ix, DSI_DSIPHY_CFG2);
+ DUMPREG(ix, DSI_DSIPHY_CFG5);
+
+ DUMPREG(ix, DSI_PLL_CONTROL);
+ DUMPREG(ix, DSI_PLL_STATUS);
+ DUMPREG(ix, DSI_PLL_GO);
+ DUMPREG(ix, DSI_PLL_CONFIGURATION1);
+ DUMPREG(ix, DSI_PLL_CONFIGURATION2);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
#undef DUMPREG
@@ -1371,15 +1472,20 @@ enum dsi_complexio_power_state {
DSI_COMPLEXIO_POWER_ULPS = 0x2,
};
-static int dsi_complexio_power(enum dsi_complexio_power_state state)
+static int dsi_complexio_power(enum omap_dsi_index ix,
+ enum dsi_complexio_power_state state)
{
int t = 0;
/* PWR_CMD */
- REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
+ REG_FLD_MOD(ix, DSI_COMPLEXIO_CFG1, state, 28, 27);
+
+ if (cpu_is_omap44xx())
+ /*bit 30 has to be set to 1 to GO in omap4*/
+ REG_FLD_MOD(ix, DSI_COMPLEXIO_CFG1, 1, 30, 30);
/* PWR_STATUS */
- while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
+ while (FLD_GET(dsi_read_reg(ix, DSI_COMPLEXIO_CFG1), 26, 25) != state) {
if (++t > 1000) {
DSSERR("failed to set complexio power state to "
"%d\n", state);
@@ -1394,6 +1500,8 @@ static int dsi_complexio_power(enum dsi_complexio_power_state state)
static void dsi_complexio_config(struct omap_dss_device *dssdev)
{
u32 r;
+ enum omap_dsi_index ix;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
int clk_lane = dssdev->phy.dsi.clk_lane;
int data1_lane = dssdev->phy.dsi.data1_lane;
@@ -1402,14 +1510,14 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
int data1_pol = dssdev->phy.dsi.data1_pol;
int data2_pol = dssdev->phy.dsi.data2_pol;
- r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+ r = dsi_read_reg(ix, DSI_COMPLEXIO_CFG1);
r = FLD_MOD(r, clk_lane, 2, 0);
r = FLD_MOD(r, clk_pol, 3, 3);
r = FLD_MOD(r, data1_lane, 6, 4);
r = FLD_MOD(r, data1_pol, 7, 7);
r = FLD_MOD(r, data2_lane, 10, 8);
r = FLD_MOD(r, data2_pol, 11, 11);
- dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
+ dsi_write_reg(ix, DSI_COMPLEXIO_CFG1, r);
/* The configuration of the DSI complex I/O (number of data lanes,
position, differential order) should not be changed while
@@ -1430,20 +1538,22 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
*/
}
-static inline unsigned ns2ddr(unsigned ns)
+static inline unsigned ns2ddr(enum omap_dsi_index ix, unsigned ns)
{
/* convert time in ns to ddr ticks, rounding up */
- unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ unsigned long ddr_clk = p_dsi->current_cinfo.clkin4ddr / 4;
return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
}
-static inline unsigned ddr2ns(unsigned ddr)
+static inline unsigned ddr2ns(enum omap_dsi_index ix, unsigned ddr)
{
- unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ unsigned long ddr_clk = p_dsi->current_cinfo.clkin4ddr / 4;
return ddr * 1000 * 1000 / (ddr_clk / 1000);
}
-static void dsi_complexio_timings(void)
+static void dsi_complexio_timings(enum omap_dsi_index ix)
{
u32 r;
u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
@@ -1455,80 +1565,85 @@ static void dsi_complexio_timings(void)
/* 1 * DDR_CLK = 2 * UI */
/* min 40ns + 4*UI max 85ns + 6*UI */
- ths_prepare = ns2ddr(70) + 2;
+ ths_prepare = ns2ddr(ix, 70) + 2;
/* min 145ns + 10*UI */
- ths_prepare_ths_zero = ns2ddr(175) + 2;
+ ths_prepare_ths_zero = ns2ddr(ix, 175) + 2;
/* min max(8*UI, 60ns+4*UI) */
- ths_trail = ns2ddr(60) + 5;
+ ths_trail = ns2ddr(ix, 60) + 5;
/* min 100ns */
- ths_exit = ns2ddr(145);
+ ths_exit = ns2ddr(ix, 145);
/* tlpx min 50n */
- tlpx_half = ns2ddr(25);
+ tlpx_half = ns2ddr(ix, 25);
/* min 60ns */
- tclk_trail = ns2ddr(60) + 2;
+ tclk_trail = ns2ddr(ix, 60) + 2;
/* min 38ns, max 95ns */
- tclk_prepare = ns2ddr(65);
+ tclk_prepare = ns2ddr(ix, 65);
/* min tclk-prepare + tclk-zero = 300ns */
- tclk_zero = ns2ddr(260);
+ tclk_zero = ns2ddr(ix, 260);
DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
- ths_prepare, ddr2ns(ths_prepare),
- ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
+ ths_prepare, ddr2ns(ix, ths_prepare),
+ ths_prepare_ths_zero, ddr2ns(ix, ths_prepare_ths_zero));
DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
- ths_trail, ddr2ns(ths_trail),
- ths_exit, ddr2ns(ths_exit));
+ ths_trail, ddr2ns(ix, ths_trail),
+ ths_exit, ddr2ns(ix, ths_exit));
DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
"tclk_zero %u (%uns)\n",
- tlpx_half, ddr2ns(tlpx_half),
- tclk_trail, ddr2ns(tclk_trail),
- tclk_zero, ddr2ns(tclk_zero));
+ tlpx_half, ddr2ns(ix, tlpx_half),
+ tclk_trail, ddr2ns(ix, tclk_trail),
+ tclk_zero, ddr2ns(ix, tclk_zero));
DSSDBG("tclk_prepare %u (%uns)\n",
- tclk_prepare, ddr2ns(tclk_prepare));
+ tclk_prepare, ddr2ns(ix, tclk_prepare));
/* program timings */
- r = dsi_read_reg(DSI_DSIPHY_CFG0);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG0);
r = FLD_MOD(r, ths_prepare, 31, 24);
r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
r = FLD_MOD(r, ths_trail, 15, 8);
r = FLD_MOD(r, ths_exit, 7, 0);
- dsi_write_reg(DSI_DSIPHY_CFG0, r);
+ dsi_write_reg(ix, DSI_DSIPHY_CFG0, r);
- r = dsi_read_reg(DSI_DSIPHY_CFG1);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG1);
r = FLD_MOD(r, tlpx_half, 22, 16);
r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0);
- dsi_write_reg(DSI_DSIPHY_CFG1, r);
+ dsi_write_reg(ix, DSI_DSIPHY_CFG1, r);
- r = dsi_read_reg(DSI_DSIPHY_CFG2);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG2);
r = FLD_MOD(r, tclk_prepare, 7, 0);
- dsi_write_reg(DSI_DSIPHY_CFG2, r);
+ dsi_write_reg(ix, DSI_DSIPHY_CFG2, r);
}
static int dsi_complexio_init(struct omap_dss_device *dssdev)
{
int r = 0;
+ enum omap_dsi_index ix;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
DSSDBG("dsi_complexio_init\n");
/* CIO_CLK_ICG, enable L3 clk to CIO */
- REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, 1, 14, 14);
+
+ if (cpu_is_omap44xx())
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, 1, 13, 13);
/* A dummy read using the SCP interface to any DSIPHY register is
* required after DSIPHY reset to complete the reset of the DSI complex
* I/O. */
- dsi_read_reg(DSI_DSIPHY_CFG5);
+ dsi_read_reg(ix, DSI_DSIPHY_CFG5);
- if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
+ if (wait_for_bit_change(ix, DSI_DSIPHY_CFG5, 30, 1) != 1) {
DSSERR("ComplexIO PHY not coming out of reset.\n");
r = -ENODEV;
goto err;
@@ -1536,24 +1651,26 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
dsi_complexio_config(dssdev);
- r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
+ r = dsi_complexio_power(ix, DSI_COMPLEXIO_POWER_ON);
if (r)
goto err;
- if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
+ if (wait_for_bit_change(ix, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
DSSERR("ComplexIO not coming out of reset.\n");
r = -ENODEV;
goto err;
}
- if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
- DSSERR("ComplexIO LDO power down.\n");
- r = -ENODEV;
- goto err;
+ if (!cpu_is_omap44xx()) {
+ if (wait_for_bit_change(ix, DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
+ DSSERR("ComplexIO LDO power down.\n");
+ r = -ENODEV;
+ goto err;
+ }
}
- dsi_complexio_timings();
+ dsi_complexio_timings(ix);
/*
The configuration of the DSI complex I/O (number of data lanes,
@@ -1567,27 +1684,27 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
bit to 1. If the sequence is not followed, the DSi complex I/O
configuration is undetermined.
*/
- dsi_if_enable(1);
- dsi_if_enable(0);
- REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
- dsi_if_enable(1);
- dsi_if_enable(0);
+ dsi_if_enable(ix, 1);
+ dsi_if_enable(ix, 0);
+ REG_FLD_MOD(ix, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
+ dsi_if_enable(ix, 1);
+ dsi_if_enable(ix, 0);
DSSDBG("CIO init done\n");
err:
return r;
}
-static void dsi_complexio_uninit(void)
+static void dsi_complexio_uninit(enum omap_dsi_index ix)
{
- dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
+ dsi_complexio_power(ix, DSI_COMPLEXIO_POWER_OFF);
}
-static int _dsi_wait_reset(void)
+static int _dsi_wait_reset(enum omap_dsi_index ix)
{
int t = 0;
- while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
+ while (REG_GET(ix, DSI_SYSSTATUS, 0, 0) == 0) {
if (++t > 5) {
DSSERR("soft reset failed\n");
return -ENODEV;
@@ -1598,42 +1715,44 @@ static int _dsi_wait_reset(void)
return 0;
}
-static int _dsi_reset(void)
+static int _dsi_reset(enum omap_dsi_index ix)
{
/* Soft reset */
- REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
- return _dsi_wait_reset();
+ REG_FLD_MOD(ix, DSI_SYSCONFIG, 1, 1, 1);
+ return _dsi_wait_reset(ix);
}
-static void dsi_reset_tx_fifo(int channel)
+static void dsi_reset_tx_fifo(enum omap_dsi_index ix, int channel)
{
u32 mask;
u32 l;
/* set fifosize of the channel to 0, then return the old size */
- l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
+ l = dsi_read_reg(ix, DSI_TX_FIFO_VC_SIZE);
mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
- dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
+ dsi_write_reg(ix, DSI_TX_FIFO_VC_SIZE, l & ~mask);
- dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
+ dsi_write_reg(ix, DSI_TX_FIFO_VC_SIZE, l);
}
-static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
- enum fifo_size size3, enum fifo_size size4)
+static void dsi_config_tx_fifo(enum omap_dsi_index ix,
+ enum fifo_size size1, enum fifo_size size2,
+ enum fifo_size size3, enum fifo_size size4)
{
u32 r = 0;
int add = 0;
int i;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- dsi.vc[0].fifo_size = size1;
- dsi.vc[1].fifo_size = size2;
- dsi.vc[2].fifo_size = size3;
- dsi.vc[3].fifo_size = size4;
+ p_dsi->vc[0].fifo_size = size1;
+ p_dsi->vc[1].fifo_size = size2;
+ p_dsi->vc[2].fifo_size = size3;
+ p_dsi->vc[3].fifo_size = size4;
for (i = 0; i < 4; i++) {
u8 v;
- int size = dsi.vc[i].fifo_size;
+ int size = p_dsi->vc[i].fifo_size;
if (add + size > 4) {
DSSERR("Illegal FIFO configuration\n");
@@ -1646,24 +1765,26 @@ static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
add += size;
}
- dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
+ dsi_write_reg(ix, DSI_TX_FIFO_VC_SIZE, r);
}
-static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
- enum fifo_size size3, enum fifo_size size4)
+static void dsi_config_rx_fifo(enum omap_dsi_index ix,
+ enum fifo_size size1, enum fifo_size size2,
+ enum fifo_size size3, enum fifo_size size4)
{
u32 r = 0;
int add = 0;
int i;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- dsi.vc[0].fifo_size = size1;
- dsi.vc[1].fifo_size = size2;
- dsi.vc[2].fifo_size = size3;
- dsi.vc[3].fifo_size = size4;
+ p_dsi->vc[0].fifo_size = size1;
+ p_dsi->vc[1].fifo_size = size2;
+ p_dsi->vc[2].fifo_size = size3;
+ p_dsi->vc[3].fifo_size = size4;
for (i = 0; i < 4; i++) {
u8 v;
- int size = dsi.vc[i].fifo_size;
+ int size = p_dsi->vc[i].fifo_size;
if (add + size > 4) {
DSSERR("Illegal FIFO configuration\n");
@@ -1676,18 +1797,18 @@ static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
add += size;
}
- dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
+ dsi_write_reg(ix, DSI_RX_FIFO_VC_SIZE, r);
}
-static int dsi_force_tx_stop_mode_io(void)
+static int dsi_force_tx_stop_mode_io(enum omap_dsi_index ix)
{
u32 r;
- r = dsi_read_reg(DSI_TIMING1);
+ r = dsi_read_reg(ix, DSI_TIMING1);
r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
- dsi_write_reg(DSI_TIMING1, r);
+ dsi_write_reg(ix, DSI_TIMING1, r);
- if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
+ if (wait_for_bit_change(ix, DSI_TIMING1, 15, 0) != 0) {
DSSERR("TX_STOP bit not going down\n");
return -EIO;
}
@@ -1695,16 +1816,18 @@ static int dsi_force_tx_stop_mode_io(void)
return 0;
}
-static int dsi_vc_enable(int channel, bool enable)
+static int dsi_vc_enable(enum omap_dsi_index ix,
+ int channel, bool enable)
{
DSSDBG("dsi_vc_enable channel %d, enable %d\n",
channel, enable);
enable = enable ? 1 : 0;
- REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
+ REG_FLD_MOD(ix, DSI_VC_CTRL(channel), enable, 0, 0);
- if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
+ if (wait_for_bit_change(ix, DSI_VC_CTRL(channel),
+ 0, enable) != enable) {
DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
return -EIO;
}
@@ -1712,13 +1835,14 @@ static int dsi_vc_enable(int channel, bool enable)
return 0;
}
-static void dsi_vc_initial_config(int channel)
+static void dsi_vc_initial_config(enum omap_dsi_index ix, int channel)
{
u32 r;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
DSSDBGF("%d", channel);
- r = dsi_read_reg(DSI_VC_CTRL(channel));
+ r = dsi_read_reg(ix, DSI_VC_CTRL(channel));
if (FLD_GET(r, 15, 15)) /* VC_BUSY */
DSSERR("VC(%d) busy when trying to configure it!\n",
@@ -1731,77 +1855,112 @@ static void dsi_vc_initial_config(int channel)
r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
-
+ if (cpu_is_omap44xx()) {
+ r = FLD_MOD(r, 3, 11, 10);
+ r = FLD_MOD(r, 3, 18, 17);
+ }
r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
- dsi_write_reg(DSI_VC_CTRL(channel), r);
+ dsi_write_reg(ix, DSI_VC_CTRL(channel), r);
- dsi.vc[channel].mode = DSI_VC_MODE_L4;
+ p_dsi->vc[channel].mode = DSI_VC_MODE_L4;
}
-static void dsi_vc_config_l4(int channel)
+static void dsi_vc_initial_config_vp(enum omap_dsi_index ix, int channel)
{
- if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
+ u32 r;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ DSSDBGF("%d", channel);
+
+ r = dsi_read_reg(ix, DSI_VC_CTRL(channel));
+ r = FLD_MOD(r, 1, 1, 1); /* SOURCE, 1 = video port */
+ r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
+ r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
+ r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
+ r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
+ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
+ r = FLD_MOD(r, 1, 9, 9); /* MODE_SPEED, high speed on/off */
+ r = FLD_MOD(r, 1, 12, 12); /*RGB565_ORDER*/
+ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
+ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
+ r = FLD_MOD(r, 1, 30, 30); /* DCS_CMD_ENABLE*/
+ r = FLD_MOD(r, 0, 31, 31); /* DCS_CMD_CODE*/
+ dsi_write_reg(ix, DSI_VC_CTRL(channel), r);
+
+ p_dsi->vc[channel].mode = DSI_VC_MODE_VP;
+}
+
+static void dsi_vc_config_l4(enum omap_dsi_index ix, int channel)
+{
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ if (p_dsi->vc[channel].mode == DSI_VC_MODE_L4)
return;
DSSDBGF("%d", channel);
- dsi_vc_enable(channel, 0);
+ dsi_vc_enable(ix, channel, 0);
- if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
+ if (REG_GET(ix, DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
DSSERR("vc(%d) busy when trying to config for L4\n", channel);
- REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
+ REG_FLD_MOD(ix, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
- dsi_vc_enable(channel, 1);
+ dsi_vc_enable(ix, channel, 1);
- dsi.vc[channel].mode = DSI_VC_MODE_L4;
+ p_dsi->vc[channel].mode = DSI_VC_MODE_L4;
}
-static void dsi_vc_config_vp(int channel)
+static void dsi_vc_config_vp(enum omap_dsi_index ix, int channel)
{
- if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ if (p_dsi->vc[channel].mode == DSI_VC_MODE_VP)
return;
DSSDBGF("%d", channel);
- dsi_vc_enable(channel, 0);
+ dsi_vc_enable(ix, channel, 0);
- if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
+ if (REG_GET(ix, DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
DSSERR("vc(%d) busy when trying to config for VP\n", channel);
- REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
+ REG_FLD_MOD(ix, DSI_VC_CTRL(channel),
+ 1, 1, 1); /* SOURCE, 1 = video port */
- dsi_vc_enable(channel, 1);
+ dsi_vc_enable(ix, channel, 1);
- dsi.vc[channel].mode = DSI_VC_MODE_VP;
+ p_dsi->vc[channel].mode = DSI_VC_MODE_VP;
}
-void omapdss_dsi_vc_enable_hs(int channel, bool enable)
+void omapdss_dsi_vc_enable_hs(enum omap_dsi_index ix,
+ int channel, bool enable)
{
DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
- WARN_ON(!dsi_bus_is_locked());
+ WARN_ON(!dsi_bus_is_locked(ix));
- dsi_vc_enable(channel, 0);
- dsi_if_enable(0);
+ dsi_vc_enable(ix, channel, 0);
+ dsi_if_enable(ix, 0);
- REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
+ REG_FLD_MOD(ix, DSI_VC_CTRL(channel), enable, 9, 9);
- dsi_vc_enable(channel, 1);
- dsi_if_enable(1);
+ dsi_vc_enable(ix, channel, 1);
+ dsi_if_enable(ix, 1);
- dsi_force_tx_stop_mode_io();
+ dsi_force_tx_stop_mode_io(ix);
}
EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
-static void dsi_vc_flush_long_data(int channel)
+static void dsi_vc_flush_long_data(enum omap_dsi_index ix,
+ int channel)
{
- while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+ while (REG_GET(ix, DSI_VC_CTRL(channel), 20, 20)) {
u32 val;
- val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+ val = dsi_read_reg(ix, DSI_VC_SHORT_PACKET_HEADER(channel));
DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
(val >> 0) & 0xff,
(val >> 8) & 0xff,
@@ -1847,18 +2006,20 @@ static void dsi_show_rx_ack_with_err(u16 err)
DSSERR("\t\tDSI Protocol Violation\n");
}
-static u16 dsi_vc_flush_receive_data(int channel)
+static u16 dsi_vc_flush_receive_data(enum omap_dsi_index ix,
+ int channel)
{
/* RX_FIFO_NOT_EMPTY */
- while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+ while (REG_GET(ix, DSI_VC_CTRL(channel), 20, 20)) {
u32 val;
u8 dt;
- val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+ val = dsi_read_reg(ix, DSI_VC_SHORT_PACKET_HEADER(channel));
DSSDBG("\trawval %#08x\n", val);
dt = FLD_GET(val, 5, 0);
if (dt == DSI_DT_RX_ACK_WITH_ERR) {
u16 err = FLD_GET(val, 23, 8);
- dsi_show_rx_ack_with_err(err);
+ if (!cpu_is_omap44xx())
+ dsi_show_rx_ack_with_err(err);
} else if (dt == DSI_DT_RX_SHORT_READ_1) {
DSSDBG("\tDCS short response, 1 byte: %#x\n",
FLD_GET(val, 23, 8));
@@ -1868,7 +2029,7 @@ static u16 dsi_vc_flush_receive_data(int channel)
} else if (dt == DSI_DT_RX_DCS_LONG_READ) {
DSSDBG("\tDCS long response, len %d\n",
FLD_GET(val, 23, 8));
- dsi_vc_flush_long_data(channel);
+ dsi_vc_flush_long_data(ix, channel);
} else {
DSSERR("\tunknown datatype 0x%02x\n", dt);
}
@@ -1876,74 +2037,84 @@ static u16 dsi_vc_flush_receive_data(int channel)
return 0;
}
-static int dsi_vc_send_bta(int channel)
+static int dsi_vc_send_bta(enum omap_dsi_index ix, int channel)
{
- if (dsi.debug_write || dsi.debug_read)
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ if (p_dsi->debug_write || p_dsi->debug_read)
DSSDBG("dsi_vc_send_bta %d\n", channel);
- WARN_ON(!dsi_bus_is_locked());
+ WARN_ON(!dsi_bus_is_locked(ix));
- if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
- DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
- dsi_vc_flush_receive_data(channel);
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(ix, DSI_VC_CTRL(channel), 20, 20)) {
+ if (!cpu_is_omap44xx())
+ DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
+ dsi_vc_flush_receive_data(ix, channel);
}
- REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
+ REG_FLD_MOD(ix, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
return 0;
}
-int dsi_vc_send_bta_sync(int channel)
+int dsi_vc_send_bta_sync(enum omap_dsi_index ix,
+ int channel)
{
int r = 0;
u32 err;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- INIT_COMPLETION(dsi.bta_completion);
+ INIT_COMPLETION(p_dsi->bta_completion);
- dsi_vc_enable_bta_irq(channel);
+ dsi_vc_enable_bta_irq(ix, channel);
- r = dsi_vc_send_bta(channel);
+ r = dsi_vc_send_bta(ix, channel);
if (r)
goto err;
- if (wait_for_completion_timeout(&dsi.bta_completion,
+ if (wait_for_completion_timeout(&p_dsi->bta_completion,
msecs_to_jiffies(500)) == 0) {
DSSERR("Failed to receive BTA\n");
r = -EIO;
goto err;
}
- err = dsi_get_errors();
+ err = dsi_get_errors(ix);
if (err) {
DSSERR("Error while sending BTA: %x\n", err);
r = -EIO;
goto err;
}
err:
- dsi_vc_disable_bta_irq(channel);
+ dsi_vc_disable_bta_irq(ix, channel);
return r;
}
EXPORT_SYMBOL(dsi_vc_send_bta_sync);
-static inline void dsi_vc_write_long_header(int channel, u8 data_type,
+static inline void dsi_vc_write_long_header(enum omap_dsi_index ix,
+ int channel, u8 data_type,
u16 len, u8 ecc)
{
u32 val;
u8 data_id;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+ WARN_ON(!dsi_bus_is_locked(ix));
- WARN_ON(!dsi_bus_is_locked());
-
- data_id = data_type | channel << 6;
+ if (cpu_is_omap44xx())
+ data_id = data_type | p_dsi->vc[channel].dest_per << 6;
+ else
+ data_id = data_type | channel << 6;
val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
FLD_VAL(ecc, 31, 24);
- dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
+ dsi_write_reg(ix, DSI_VC_LONG_PACKET_HEADER(channel), val);
}
-static inline void dsi_vc_write_long_payload(int channel,
- u8 b1, u8 b2, u8 b3, u8 b4)
+static inline void dsi_vc_write_long_payload(enum omap_dsi_index ix,
+ int channel, u8 b1, u8 b2, u8 b3, u8 b4)
{
u32 val;
@@ -1952,10 +2123,11 @@ static inline void dsi_vc_write_long_payload(int channel,
/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
b1, b2, b3, b4, val); */
- dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
+ dsi_write_reg(ix, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
}
-static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
+static int dsi_vc_send_long(enum omap_dsi_index ix, int channel,
+ u8 data_type, u8 *data, u16 len,
u8 ecc)
{
/*u32 val; */
@@ -1963,23 +2135,24 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
u8 *p;
int r = 0;
u8 b1, b2, b3, b4;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- if (dsi.debug_write)
+ if (p_dsi->debug_write)
DSSDBG("dsi_vc_send_long, %d bytes\n", len);
/* len + header */
- if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
+ if (p_dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
DSSERR("unable to send long packet: packet too long.\n");
return -EINVAL;
}
- dsi_vc_config_l4(channel);
+ dsi_vc_config_l4(ix, channel);
- dsi_vc_write_long_header(channel, data_type, len, ecc);
+ dsi_vc_write_long_header(ix, channel, data_type, len, ecc);
p = data;
for (i = 0; i < len >> 2; i++) {
- if (dsi.debug_write)
+ if (p_dsi->debug_write)
DSSDBG("\tsending full packet %d\n", i);
b1 = *p++;
@@ -1987,14 +2160,14 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
b3 = *p++;
b4 = *p++;
- dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
+ dsi_vc_write_long_payload(ix, channel, b1, b2, b3, b4);
}
i = len % 4;
if (i) {
b1 = 0; b2 = 0; b3 = 0;
- if (dsi.debug_write)
+ if (p_dsi->debug_write)
DSSDBG("\tsending remainder bytes %d\n", i);
switch (i) {
@@ -2012,62 +2185,68 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
break;
}
- dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
+ dsi_vc_write_long_payload(ix, channel, b1, b2, b3, 0);
}
return r;
}
-static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
+static int dsi_vc_send_short(enum omap_dsi_index ix,
+ int channel, u8 data_type, u16 data, u8 ecc)
{
u32 r;
u8 data_id;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- WARN_ON(!dsi_bus_is_locked());
+ WARN_ON(!dsi_bus_is_locked(ix));
- if (dsi.debug_write)
+ if (p_dsi->debug_write)
DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
channel,
data_type, data & 0xff, (data >> 8) & 0xff);
- dsi_vc_config_l4(channel);
+ dsi_vc_config_l4(ix, channel);
- if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
+ if (FLD_GET(dsi_read_reg(ix, DSI_VC_CTRL(channel)), 16, 16)) {
DSSERR("ERROR FIFO FULL, aborting transfer\n");
return -EINVAL;
}
- data_id = data_type | channel << 6;
+ if (cpu_is_omap44xx())
+ data_id = data_type | p_dsi->vc[channel].dest_per << 6;
+ else
+ data_id = data_type | channel << 6;
r = (data_id << 0) | (data << 8) | (ecc << 24);
- dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
+ dsi_write_reg(ix, DSI_VC_SHORT_PACKET_HEADER(channel), r);
return 0;
}
-int dsi_vc_send_null(int channel)
+int dsi_vc_send_null(enum omap_dsi_index ix, int channel)
{
u8 nullpkg[] = {0, 0, 0, 0};
- return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
+ return dsi_vc_send_long(ix, channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
}
EXPORT_SYMBOL(dsi_vc_send_null);
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
+int dsi_vc_dcs_write_nosync(enum omap_dsi_index ix, int channel,
+ u8 *data, int len)
{
int r;
BUG_ON(len == 0);
if (len == 1) {
- r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
+ r = dsi_vc_send_short(ix, channel, DSI_DT_DCS_SHORT_WRITE_0,
data[0], 0);
} else if (len == 2) {
- r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
+ r = dsi_vc_send_short(ix, channel, DSI_DT_DCS_SHORT_WRITE_1,
data[0] | (data[1] << 8), 0);
} else {
/* 0x39 = DCS Long Write */
- r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
+ r = dsi_vc_send_long(ix, channel, DSI_DT_DCS_LONG_WRITE,
data, len, 0);
}
@@ -2075,15 +2254,16 @@ int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
}
EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
-int dsi_vc_dcs_write(int channel, u8 *data, int len)
+int dsi_vc_dcs_write(enum omap_dsi_index ix, int channel,
+ u8 *data, int len)
{
int r;
- r = dsi_vc_dcs_write_nosync(channel, data, len);
+ r = dsi_vc_dcs_write_nosync(ix, channel, data, len);
if (r)
goto err;
- r = dsi_vc_send_bta_sync(channel);
+ r = dsi_vc_send_bta_sync(ix, channel);
if (r)
goto err;
@@ -2095,47 +2275,51 @@ err:
}
EXPORT_SYMBOL(dsi_vc_dcs_write);
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
+int dsi_vc_dcs_write_0(enum omap_dsi_index ix, int channel,
+ u8 dcs_cmd)
{
- return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
+ return dsi_vc_dcs_write(ix, channel, &dcs_cmd, 1);
}
EXPORT_SYMBOL(dsi_vc_dcs_write_0);
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param)
+int dsi_vc_dcs_write_1(enum omap_dsi_index ix, int channel,
+ u8 dcs_cmd, u8 param)
{
u8 buf[2];
buf[0] = dcs_cmd;
buf[1] = param;
- return dsi_vc_dcs_write(channel, buf, 2);
+ return dsi_vc_dcs_write(ix, channel, buf, 2);
}
EXPORT_SYMBOL(dsi_vc_dcs_write_1);
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
+int dsi_vc_dcs_read(enum omap_dsi_index ix, int channel,
+ u8 dcs_cmd, u8 *buf, int buflen)
{
u32 val;
u8 dt;
int r;
+ struct dsi_struct *p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- if (dsi.debug_read)
+ if (p_dsi->debug_read)
DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
- r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
+ r = dsi_vc_send_short(ix, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
if (r)
goto err;
- r = dsi_vc_send_bta_sync(channel);
+ r = dsi_vc_send_bta_sync(ix, channel);
if (r)
goto err;
/* RX_FIFO_NOT_EMPTY */
- if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
+ if (REG_GET(ix, DSI_VC_CTRL(channel), 20, 20) == 0) {
DSSERR("RX fifo empty when trying to read.\n");
r = -EIO;
goto err;
}
- val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
- if (dsi.debug_read)
+ val = dsi_read_reg(ix, DSI_VC_SHORT_PACKET_HEADER(channel));
+ if (p_dsi->debug_read)
DSSDBG("\theader: %08x\n", val);
dt = FLD_GET(val, 5, 0);
if (dt == DSI_DT_RX_ACK_WITH_ERR) {
@@ -2146,7 +2330,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
} else if (dt == DSI_DT_RX_SHORT_READ_1) {
u8 data = FLD_GET(val, 15, 8);
- if (dsi.debug_read)
+ if (p_dsi->debug_read)
DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
if (buflen < 1) {
@@ -2159,7 +2343,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
return 1;
} else if (dt == DSI_DT_RX_SHORT_READ_2) {
u16 data = FLD_GET(val, 23, 8);
- if (dsi.debug_read)
+ if (p_dsi->debug_read)
DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
if (buflen < 2) {
@@ -2174,7 +2358,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
} else if (dt == DSI_DT_RX_DCS_LONG_READ) {
int w;
int len = FLD_GET(val, 23, 8);
- if (dsi.debug_read)
+ if (p_dsi->debug_read)
DSSDBG("\tDCS long response, len %d\n", len);
if (len > buflen) {
@@ -2185,8 +2369,8 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
/* two byte checksum ends the packet, not included in len */
for (w = 0; w < len + 2;) {
int b;
- val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
- if (dsi.debug_read)
+ val = dsi_read_reg(ix, DSI_VC_SHORT_PACKET_HEADER(channel));
+ if (p_dsi->debug_read)
DSSDBG("\t\t%02x %02x %02x %02x\n",
(val >> 0) & 0xff,
(val >> 8) & 0xff,
@@ -2217,11 +2401,12 @@ err:
}
EXPORT_SYMBOL(dsi_vc_dcs_read);
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
+int dsi_vc_dcs_read_1(enum omap_dsi_index ix, int channel,
+ u8 dcs_cmd, u8 *data)
{
int r;
- r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
+ r = dsi_vc_dcs_read(ix, channel, dcs_cmd, data, 1);
if (r < 0)
return r;
@@ -2233,11 +2418,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
}
EXPORT_SYMBOL(dsi_vc_dcs_read_1);
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
+int dsi_vc_dcs_read_2(enum omap_dsi_index ix, int channel,
+ u8 dcs_cmd, u16 *data)
{
int r;
- r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
+ r = dsi_vc_dcs_read(ix, channel, dcs_cmd, (u8 *)data, 2);
if (r < 0)
return r;
@@ -2249,22 +2435,24 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
}
EXPORT_SYMBOL(dsi_vc_dcs_read_2);
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
+int dsi_vc_set_max_rx_packet_size(enum omap_dsi_index ix,
+ int channel, u16 len)
{
int r;
- r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
+ r = dsi_vc_send_short(ix, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
len, 0);
if (r)
return r;
- r = dsi_vc_send_bta_sync(channel);
+ r = dsi_vc_send_bta_sync(ix, channel);
return r;
}
EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
-static void dsi_set_lp_rx_timeout(unsigned long ns)
+static void dsi_set_lp_rx_timeout(enum omap_dsi_index ix,
+ unsigned long ns)
{
u32 r;
unsigned x4, x16;
@@ -2273,7 +2461,7 @@ static void dsi_set_lp_rx_timeout(unsigned long ns)
/* ticks in DSI_FCK */
- fck = dsi_fclk_rate();
+ fck = dsi_fclk_rate(ix);
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
@@ -2303,12 +2491,12 @@ static void dsi_set_lp_rx_timeout(unsigned long ns)
x16 = 1;
}
- r = dsi_read_reg(DSI_TIMING2);
+ r = dsi_read_reg(ix, DSI_TIMING2);
r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
- dsi_write_reg(DSI_TIMING2, r);
+ dsi_write_reg(ix, DSI_TIMING2, r);
DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
@@ -2316,7 +2504,8 @@ static void dsi_set_lp_rx_timeout(unsigned long ns)
ticks, x4 ? " x4" : "", x16 ? " x16" : "");
}
-static void dsi_set_ta_timeout(unsigned long ns)
+static void dsi_set_ta_timeout(enum omap_dsi_index ix,
+ unsigned long ns)
{
u32 r;
unsigned x8, x16;
@@ -2324,7 +2513,7 @@ static void dsi_set_ta_timeout(unsigned long ns)
unsigned long ticks;
/* ticks in DSI_FCK */
- fck = dsi_fclk_rate();
+ fck = dsi_fclk_rate(ix);
ticks = (fck / 1000 / 1000) * ns / 1000;
x8 = 0;
x16 = 0;
@@ -2354,12 +2543,12 @@ static void dsi_set_ta_timeout(unsigned long ns)
x16 = 1;
}
- r = dsi_read_reg(DSI_TIMING1);
+ r = dsi_read_reg(ix, DSI_TIMING1);
r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
- dsi_write_reg(DSI_TIMING1, r);
+ dsi_write_reg(ix, DSI_TIMING1, r);
DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
@@ -2367,7 +2556,8 @@ static void dsi_set_ta_timeout(unsigned long ns)
ticks, x8 ? " x8" : "", x16 ? " x16" : "");
}
-static void dsi_set_stop_state_counter(unsigned long ns)
+static void dsi_set_stop_state_counter(enum omap_dsi_index ix,
+ unsigned long ns)
{
u32 r;
unsigned x4, x16;
@@ -2376,7 +2566,7 @@ static void dsi_set_stop_state_counter(unsigned long ns)
/* ticks in DSI_FCK */
- fck = dsi_fclk_rate();
+ fck = dsi_fclk_rate(ix);
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
@@ -2407,12 +2597,12 @@ static void dsi_set_stop_state_counter(unsigned long ns)
x16 = 1;
}
- r = dsi_read_reg(DSI_TIMING1);
+ r = dsi_read_reg(ix, DSI_TIMING1);
r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
- dsi_write_reg(DSI_TIMING1, r);
+ dsi_write_reg(ix, DSI_TIMING1, r);
DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
@@ -2420,7 +2610,8 @@ static void dsi_set_stop_state_counter(unsigned long ns)
ticks, x4 ? " x4" : "", x16 ? " x16" : "");
}
-static void dsi_set_hs_tx_timeout(unsigned long ns)
+static void dsi_set_hs_tx_timeout(enum omap_dsi_index ix,
+ unsigned long ns)
{
u32 r;
unsigned x4, x16;
@@ -2429,7 +2620,7 @@ static void dsi_set_hs_tx_timeout(unsigned long ns)
/* ticks in TxByteClkHS */
- fck = dsi_get_txbyteclkhs();
+ fck = dsi_get_txbyteclkhs(ix);
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
@@ -2459,12 +2650,12 @@ static void dsi_set_hs_tx_timeout(unsigned long ns)
x16 = 1;
}
- r = dsi_read_reg(DSI_TIMING2);
+ r = dsi_read_reg(ix, DSI_TIMING2);
r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
- dsi_write_reg(DSI_TIMING2, r);
+ dsi_write_reg(ix, DSI_TIMING2, r);
DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
@@ -2475,22 +2666,27 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
{
u32 r;
int buswidth = 0;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
- dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
+ dsi_config_tx_fifo(ix, DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32);
- dsi_config_rx_fifo(DSI_FIFO_SIZE_32,
+ dsi_config_rx_fifo(ix, DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32,
DSI_FIFO_SIZE_32);
/* XXX what values for the timeouts? */
- dsi_set_stop_state_counter(1000);
- dsi_set_ta_timeout(6400000);
- dsi_set_lp_rx_timeout(48000);
- dsi_set_hs_tx_timeout(1000000);
+ dsi_set_stop_state_counter(ix, 1000);
+ dsi_set_ta_timeout(ix, 6400000);
+ dsi_set_lp_rx_timeout(ix, 48000);
+ dsi_set_hs_tx_timeout(ix, 1000000);
switch (dssdev->ctrl.pixel_size) {
case 16:
@@ -2506,26 +2702,45 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
BUG();
}
- r = dsi_read_reg(DSI_CTRL);
- r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
- r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
+ r = dsi_read_reg(ix, DSI_CTRL);
+ r = FLD_MOD(r, (cpu_is_omap44xx()) ? 0 : 1,
+ 1, 1); /* CS_RX_EN */
+ r = FLD_MOD(r, (cpu_is_omap44xx()) ? 0 : 1,
+ 2, 2); /* ECC_RX_EN */
r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
+ r = FLD_MOD(r, (cpu_is_omap44xx()) ? 1 : 0,
+ 9, 9); /*VP_DE_POL */
+ r = FLD_MOD(r, (cpu_is_omap44xx()) ? 1 : 0,
+ 11, 11); /*VP_VSYNC_POL */
r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
- r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
- r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
- r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
-
- dsi_write_reg(DSI_CTRL, r);
-
- dsi_vc_initial_config(0);
- dsi_vc_initial_config(1);
- dsi_vc_initial_config(2);
- dsi_vc_initial_config(3);
+ r = FLD_MOD(r, (cpu_is_omap44xx()) ? 0 : 1,
+ 19, 19); /* EOT_ENABLE */
+ if (cpu_is_omap34xx()) {
+ r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
+ r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE */
+ }
+ dsi_write_reg(ix, DSI_CTRL, r);
+ dsi_vc_initial_config(ix, 0);
+ if (cpu_is_omap44xx())
+ dsi_vc_initial_config_vp(ix, 1);
+ else
+ dsi_vc_initial_config(ix, 1);
+ dsi_vc_initial_config(ix, 2);
+ dsi_vc_initial_config(ix, 3);
+
+ /* In Present OMAP4 configuration, 2 VC's send data
+ * to the same peripheral */
+ if (cpu_is_omap44xx()) {
+ p_dsi->vc[0].dest_per = 0;
+ p_dsi->vc[1].dest_per = 0;
+ p_dsi->vc[2].dest_per = 0;
+ p_dsi->vc[3].dest_per = 0;
+ }
return 0;
}
@@ -2539,26 +2754,29 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
unsigned enter_hs_mode_lat, exit_hs_mode_lat;
unsigned ths_eot;
u32 r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- r = dsi_read_reg(DSI_DSIPHY_CFG0);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG0);
ths_prepare = FLD_GET(r, 31, 24);
ths_prepare_ths_zero = FLD_GET(r, 23, 16);
ths_zero = ths_prepare_ths_zero - ths_prepare;
ths_trail = FLD_GET(r, 15, 8);
ths_exit = FLD_GET(r, 7, 0);
- r = dsi_read_reg(DSI_DSIPHY_CFG1);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG1);
tlpx = FLD_GET(r, 22, 16) * 2;
tclk_trail = FLD_GET(r, 15, 8);
tclk_zero = FLD_GET(r, 7, 0);
- r = dsi_read_reg(DSI_DSIPHY_CFG2);
+ r = dsi_read_reg(ix, DSI_DSIPHY_CFG2);
tclk_prepare = FLD_GET(r, 7, 0);
/* min 8*UI */
tclk_pre = 20;
/* min 60ns + 52*UI */
- tclk_post = ns2ddr(60) + 26;
+ tclk_post = ns2ddr(ix, 60) + 26;
/* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
if (dssdev->phy.dsi.data1_lane != 0 &&
@@ -2574,10 +2792,10 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
- r = dsi_read_reg(DSI_CLK_TIMING);
+ r = dsi_read_reg(ix, DSI_CLK_TIMING);
r = FLD_MOD(r, ddr_clk_pre, 15, 8);
r = FLD_MOD(r, ddr_clk_post, 7, 0);
- dsi_write_reg(DSI_CLK_TIMING, r);
+ dsi_write_reg(ix, DSI_CLK_TIMING, r);
DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
ddr_clk_pre,
@@ -2591,7 +2809,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
FLD_VAL(exit_hs_mode_lat, 15, 0);
- dsi_write_reg(DSI_VM_TIMING7, r);
+ dsi_write_reg(ix, DSI_VM_TIMING7, r);
DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
enter_hs_mode_lat, exit_hs_mode_lat);
@@ -2601,19 +2819,19 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
#define DSI_DECL_VARS \
int __dsi_cb = 0; u32 __dsi_cv = 0;
-#define DSI_FLUSH(ch) \
+#define DSI_FLUSH(ix, ch) \
if (__dsi_cb > 0) { \
/*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
- dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
+ dsi_write_reg(ix, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
__dsi_cb = __dsi_cv = 0; \
}
-#define DSI_PUSH(ch, data) \
+#define DSI_PUSH(ix, ch, data) \
do { \
__dsi_cv |= (data) << (__dsi_cb * 8); \
/*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
if (++__dsi_cb > 3) \
- DSI_FLUSH(ch); \
+ DSI_FLUSH(ix, ch); \
} while (0)
static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
@@ -2633,9 +2851,14 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
int horiz_inc;
int current_x;
struct omap_overlay *ovl;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
debug_irq = 0;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
x, y, w, h);
@@ -2658,7 +2881,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
* in fifo */
/* When using CPU, max long packet size is TX buffer size */
- max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
+ max_dsi_packet_size = p_dsi->vc[0].fifo_size * 32 * 4;
/* we seem to get better perf if we divide the tx fifo to half,
and while the other half is being sent, we fill the other half
@@ -2687,12 +2910,12 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
#if 1
/* using fifo not empty */
/* TX_FIFO_NOT_EMPTY */
- while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
+ while (FLD_GET(dsi_read_reg(ix, DSI_VC_CTRL(0)), 5, 5)) {
fifo_stalls++;
if (fifo_stalls > 0xfffff) {
DSSERR("fifo stalls overflow, pixels left %d\n",
pixels_left);
- dsi_if_enable(0);
+ dsi_if_enable(ix, 0);
return -EIO;
}
udelay(1);
@@ -2724,17 +2947,17 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
pixels_left -= pixels;
- dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
+ dsi_vc_write_long_header(ix, 0, DSI_DT_DCS_LONG_WRITE,
1 + pixels * bytespp, 0);
- DSI_PUSH(0, dcs_cmd);
+ DSI_PUSH(ix, 0, dcs_cmd);
while (pixels-- > 0) {
u32 pix = __raw_readl(data++);
- DSI_PUSH(0, (pix >> 16) & 0xff);
- DSI_PUSH(0, (pix >> 8) & 0xff);
- DSI_PUSH(0, (pix >> 0) & 0xff);
+ DSI_PUSH(ix, 0, (pix >> 16) & 0xff);
+ DSI_PUSH(ix, 0, (pix >> 8) & 0xff);
+ DSI_PUSH(ix, 0, (pix >> 0) & 0xff);
current_x++;
if (current_x == x+w) {
@@ -2743,7 +2966,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
}
}
- DSI_FLUSH(0);
+ DSI_FLUSH(ix, 0);
}
return 0;
@@ -2759,16 +2982,26 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
unsigned packet_payload;
unsigned packet_len;
u32 l;
- const unsigned channel = dsi.update_channel;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+ unsigned channel;
+ bool use_te_trigger;
/* line buffer is 1024 x 24bits */
/* XXX: for some reason using full buffer size causes considerable TX
* slowdown with update sizes that fill the whole buffer */
const unsigned line_buf_size = 1023 * 3;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ channel = p_dsi->update_channel;
+
+ use_te_trigger = p_dsi->te_enabled && !p_dsi->use_ext_te;
+
DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
x, y, w, h);
- dsi_vc_config_vp(channel);
+ dsi_vc_config_vp(ix, channel);
bytespp = dssdev->ctrl.pixel_size / 8;
bytespl = w * bytespp;
@@ -2789,15 +3022,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
total_len += (bytespf % packet_payload) + 1;
l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
- dsi_write_reg(DSI_VC_TE(channel), l);
+ dsi_write_reg(ix, DSI_VC_TE(channel), l);
- dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
+ dsi_vc_write_long_header(ix, channel, DSI_DT_DCS_LONG_WRITE,
+ packet_len, 0);
- if (dsi.te_enabled)
+ if (use_te_trigger)
l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
else
l = FLD_MOD(l, 1, 31, 31); /* TE_START */
- dsi_write_reg(DSI_VC_TE(channel), l);
+ dsi_write_reg(ix, DSI_VC_TE(channel), l);
/* We put SIDLEMODE to no-idle for the duration of the transfer,
* because DSS interrupts are not capable of waking up the CPU and the
@@ -2807,22 +3041,24 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
*/
dispc_disable_sidle();
- dsi_perf_mark_start();
+ dsi_perf_mark_start(ix);
- schedule_delayed_work(&dsi.framedone_timeout_work,
+ schedule_delayed_work(&p_dsi->framedone_timeout_work,
msecs_to_jiffies(250));
dss_start_update(dssdev);
- if (dsi.te_enabled) {
+ if (use_te_trigger) {
/* disable LP_RX_TO, so that we can receive TE. Time to wait
* for TE is longer than the timer allows */
- REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
-
- dsi_vc_send_bta(channel);
+ REG_FLD_MOD(ix, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
+ if (cpu_is_omap44xx())
+ dsi_vc_send_bta(ix, 0);
+ else
+ dsi_vc_send_bta(ix, channel);
#ifdef DSI_CATCH_MISSING_TE
- mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
+ mod_timer(&p_dsi->te_timer, jiffies + msecs_to_jiffies(250));
#endif
}
}
@@ -2830,23 +3066,37 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
#ifdef DSI_CATCH_MISSING_TE
static void dsi_te_timeout(unsigned long arg)
{
- DSSERR("TE not received for 250ms!\n");
+ DSSERR("DSI TE not received for 250ms!\n");
+}
+
+static void dsi2_te_timeout(unsigned long arg)
+{
+ DSSERR("DSI2 TE not received for 250ms!\n");
}
#endif
static void dsi_framedone_timeout_work_callback(struct work_struct *work)
{
int r;
- const int channel = dsi.update_channel;
+ int channel;
+
+ if (!cpu_is_omap44xx())
+ channel = dsi1.update_channel;
+ else
+ channel = 0;
DSSERR("Framedone not received for 250ms!\n");
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
- if (dsi.te_enabled) {
+ if (cpu_is_omap44xx())
+ /* Ensures recovery of DISPC after a failed lcd_enable*/
+ dispc_enable_lcd_out(OMAP_DSS_CHANNEL_LCD, 0);
+
+ if (dsi1.te_enabled) {
/* enable LP_RX_TO again after the TE */
- REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+ REG_FLD_MOD(DSI1, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
/* Send BTA after the frame. We need this for the TE to work, as TE
@@ -2858,17 +3108,63 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
* make sure that the transfer has been completed. It would be more
* optimal, but more complex, to wait only just before starting next
* transfer. */
- r = dsi_vc_send_bta_sync(channel);
+ r = dsi_vc_send_bta_sync(DSI1, channel);
if (r)
DSSERR("BTA after framedone failed\n");
/* RX_FIFO_NOT_EMPTY */
- if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+ if (REG_GET(DSI1, DSI_VC_CTRL(channel), 20, 20)) {
+ DSSERR("Received error during frame transfer:\n");
+ dsi_vc_flush_receive_data(DSI1, channel);
+ }
+
+ dsi1.framedone_callback(-ETIMEDOUT, dsi1.framedone_data);
+}
+
+static void dsi2_framedone_timeout_work_callback(struct work_struct *work)
+{
+ int r;
+ int channel;
+
+ if (!cpu_is_omap44xx())
+ channel = dsi2.update_channel;
+ else
+ channel = 0;
+
+ DSSERR("Framedone2 not received for 250ms!\n");
+
+ /* SIDLEMODE back to smart-idle */
+ dispc_enable_sidle();
+
+ if (cpu_is_omap44xx())
+ /* Ensures recovery of DISPC after a failed lcd_enable*/
+ dispc_enable_lcd_out(OMAP_DSS_CHANNEL_LCD2, 0);
+
+ if (dsi2.te_enabled) {
+ /* enable LP_RX_TO again after the TE */
+ REG_FLD_MOD(DSI2, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+ }
+
+ /* Send BTA after the frame. We need this for the TE to work, as TE
+ * trigger is only sent for BTAs without preceding packet. Thus we need
+ * to BTA after the pixel packets so that next BTA will cause TE
+ * trigger.
+ *
+ * This is not needed when TE is not in use, but we do it anyway to
+ * make sure that the transfer has been completed. It would be more
+ * optimal, but more complex, to wait only just before starting next
+ * transfer. */
+ r = dsi_vc_send_bta_sync(DSI2, channel);
+ if (r)
+ DSSERR("BTA after framedone2 failed\n");
+
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(DSI2, DSI_VC_CTRL(channel), 20, 20)) {
DSSERR("Received error during frame transfer:\n");
- dsi_vc_flush_receive_data(channel);
+ dsi_vc_flush_receive_data(DSI2, channel);
}
- dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
+ dsi2.framedone_callback(-ETIMEDOUT, dsi2.framedone_data);
}
static void dsi_framedone_irq_callback(void *data, u32 mask)
@@ -2880,20 +3176,41 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
+ schedule_work(&dsi1.framedone_work);
+}
- schedule_work(&dsi.framedone_work);
+static void dsi2_framedone_irq_callback(void *data, u32 mask)
+{
+ /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
+ * turns itself off. However, DSI still has the pixels in its buffers,
+ * and is sending the data.
+ */
+
+ /* SIDLEMODE back to smart-idle */
+ dispc_enable_sidle();
+ schedule_work(&dsi2.framedone_work);
}
-static void dsi_handle_framedone(void)
+static void dsi_handle_framedone(enum omap_dsi_index ix)
{
int r;
- const int channel = dsi.update_channel;
+ int channel;
+ struct dsi_struct *p_dsi;
+ bool use_te_trigger;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ use_te_trigger = p_dsi->te_enabled && !p_dsi->use_ext_te;
+
+ if (!cpu_is_omap44xx())
+ channel = p_dsi->update_channel;
+ else
+ channel = 0;
DSSDBG("FRAMEDONE\n");
- if (dsi.te_enabled) {
+ if (use_te_trigger) {
/* enable LP_RX_TO again after the TE */
- REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+ REG_FLD_MOD(ix, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
/* Send BTA after the frame. We need this for the TE to work, as TE
@@ -2905,18 +3222,19 @@ static void dsi_handle_framedone(void)
* make sure that the transfer has been completed. It would be more
* optimal, but more complex, to wait only just before starting next
* transfer. */
- r = dsi_vc_send_bta_sync(channel);
+ r = dsi_vc_send_bta_sync(ix, channel);
if (r)
DSSERR("BTA after framedone failed\n");
/* RX_FIFO_NOT_EMPTY */
- if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
- DSSERR("Received error during frame transfer:\n");
- dsi_vc_flush_receive_data(channel);
+ if (REG_GET(ix, DSI_VC_CTRL(channel), 20, 20)) {
+ if (!cpu_is_omap44xx())
+ DSSERR("Received error during frame transfer:\n");
+ dsi_vc_flush_receive_data(ix, channel);
}
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
- dispc_fake_vsync_irq();
+ dispc_fake_vsync_irq(ix);
#endif
}
@@ -2924,19 +3242,35 @@ static void dsi_framedone_work_callback(struct work_struct *work)
{
DSSDBGF();
- cancel_delayed_work_sync(&dsi.framedone_timeout_work);
+ cancel_delayed_work_sync(&dsi1.framedone_timeout_work);
- dsi_handle_framedone();
+ dsi_handle_framedone(DSI1);
- dsi_perf_show("DISPC");
+ dsi_perf_show(DSI1, "DISPC");
- dsi.framedone_callback(0, dsi.framedone_data);
+ dsi1.framedone_callback(0, dsi1.framedone_data);
+}
+
+static void dsi2_framedone_work_callback(struct work_struct *work)
+{
+ DSSDBGF();
+
+ cancel_delayed_work_sync(&dsi2.framedone_timeout_work);
+
+ dsi_handle_framedone(DSI2);
+
+ dsi_perf_show(DSI2, "DISPC");
+
+ dsi2.framedone_callback(0, dsi2.framedone_data);
}
int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h)
{
u16 dw, dh;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
dssdev->driver->get_resolution(dssdev, &dw, &dh);
@@ -2955,11 +3289,11 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
if (*w == 0 || *h == 0)
return -EINVAL;
- dsi_perf_mark_setup();
+ dsi_perf_mark_setup(ix);
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h);
- dispc_set_lcd_size(*w, *h);
+ dispc_set_lcd_size(dssdev->channel, *w, *h);
}
return 0;
@@ -2971,22 +3305,28 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h,
void (*callback)(int, void *), void *data)
{
- dsi.update_channel = channel;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ p_dsi->update_channel = channel;
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- dsi.framedone_callback = callback;
- dsi.framedone_data = data;
+ p_dsi->framedone_callback = callback;
+ p_dsi->framedone_data = data;
- dsi.update_region.x = x;
- dsi.update_region.y = y;
- dsi.update_region.w = w;
- dsi.update_region.h = h;
- dsi.update_region.device = dssdev;
+ p_dsi->update_region.x = x;
+ p_dsi->update_region.y = y;
+ p_dsi->update_region.w = w;
+ p_dsi->update_region.h = h;
+ p_dsi->update_region.device = dssdev;
dsi_update_screen_dispc(dssdev, x, y, w, h);
} else {
dsi_update_screen_l4(dssdev, x, y, w, h);
- dsi_perf_show("L4");
+ dsi_perf_show(ix, "L4");
callback(0, data);
}
@@ -3000,21 +3340,42 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
{
int r;
- r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
- DISPC_IRQ_FRAMEDONE);
+ r = omap_dispc_register_isr((dssdev->channel == OMAP_DSS_CHANNEL_LCD) ?
+ dsi_framedone_irq_callback : dsi2_framedone_irq_callback,
+ NULL, (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2);
if (r) {
DSSERR("can't get FRAMEDONE irq\n");
return r;
}
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+ dispc_set_lcd_display_type(dssdev->channel,
+ OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
+ dispc_set_parallel_interface_mode(dssdev->channel,
+ OMAP_DSS_PARALLELMODE_DSI);
dispc_enable_fifohandcheck(1);
- dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+ dispc_set_tft_data_lines(dssdev->channel, dssdev->ctrl.pixel_size);
+
+ if (cpu_is_omap44xx())
+ dispc_set_pol_freq(dssdev->channel, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
- {
+ if (cpu_is_omap44xx()) {
+ struct omap_video_timings timings = {
+ .hsw = 4+1,
+ .hfp = 4+1,
+ .hbp = 4+1,
+ .vsw = 0+1,
+ .vfp = 0,
+ .vbp = 1,
+ .x_res = 864,
+ .y_res = 480,
+ };
+
+ dispc_set_lcd_timings(dssdev->channel, &timings);
+ } else {
struct omap_video_timings timings = {
.hsw = 1,
.hfp = 1,
@@ -3024,7 +3385,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
.vbp = 0,
};
- dispc_set_lcd_timings(&timings);
+ dispc_set_lcd_timings(dssdev->channel, &timings);
}
return 0;
@@ -3032,14 +3393,19 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
{
- omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
- DISPC_IRQ_FRAMEDONE);
+ omap_dispc_unregister_isr((dssdev->channel == OMAP_DSS_CHANNEL_LCD) ?
+ dsi_framedone_irq_callback : dsi2_framedone_irq_callback,
+ NULL, (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2);
}
static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
{
struct dsi_clock_info cinfo;
int r;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
/* we always use DSS2_FCK as input clock */
cinfo.use_dss2_fck = true;
@@ -3051,7 +3417,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
if (r)
return r;
- r = dsi_pll_set_clock_div(&cinfo);
+ r = dsi_pll_set_clock_div(ix, &cinfo);
if (r) {
DSSERR("Failed to set dsi clocks\n");
return r;
@@ -3065,8 +3431,11 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
struct dispc_clock_info dispc_cinfo;
int r;
unsigned long long fck;
+ enum omap_dsi_index ix;
- fck = dsi_get_dsi1_pll_rate();
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+
+ fck = dsi_get_dsi1_pll_rate(ix);
dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
@@ -3077,7 +3446,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
return r;
}
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(dssdev->channel, &dispc_cinfo);
if (r) {
DSSERR("Failed to set dispc clocks\n");
return r;
@@ -3088,9 +3457,15 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
{
- int r;
+ int r, l = 0;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
- _dsi_print_reset_status();
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
+ _dsi_print_reset_status(ix);
r = dsi_pll_init(dssdev, true, true);
if (r)
@@ -3100,8 +3475,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err1;
- dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
+ if (cpu_is_omap44xx())
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ else
+ dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+ dss_select_dsi_clk_source(ix, DSS_SRC_DSI2_PLL_FCLK);
DSSDBG("PLL OK\n");
@@ -3113,58 +3491,81 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err2;
- _dsi_print_reset_status();
+ _dsi_print_reset_status(ix);
dsi_proto_timings(dssdev);
dsi_set_lp_clk_divisor(dssdev);
if (1)
- _dsi_print_reset_status();
+ _dsi_print_reset_status(ix);
r = dsi_proto_config(dssdev);
if (r)
goto err3;
/* enable interface */
- dsi_vc_enable(0, 1);
- dsi_vc_enable(1, 1);
- dsi_vc_enable(2, 1);
- dsi_vc_enable(3, 1);
- dsi_if_enable(1);
- dsi_force_tx_stop_mode_io();
+ dsi_vc_enable(ix, 0, 1);
+ dsi_vc_enable(ix, 1, 1);
+ dsi_vc_enable(ix, 2, 1);
+ dsi_vc_enable(ix, 3, 1);
+ dsi_if_enable(ix, 1);
+ dsi_force_tx_stop_mode_io(ix);
+
+ /* magic OMAP4 registers */
+ dsi_write_reg(ix, DSI_DSIPHY_CFG12, 0x58);
+
+ l = dsi_read_reg(ix, DSI_DSIPHY_CFG14);
+ l = FLD_MOD(l, 1, 31, 31);
+ l = FLD_MOD(l, 0x54, 30, 23);
+ l = FLD_MOD(l, 1, 19, 19);
+ l = FLD_MOD(l, 1, 18, 18);
+ l = FLD_MOD(l, 7, 17, 14);
+ l = FLD_MOD(l, 1, 11, 11);
+ dsi_write_reg(ix, DSI_DSIPHY_CFG14, l);
+
+ l = 0;
+ l = dsi_read_reg(ix, DSI_DSIPHY_CFG8);
+ l = FLD_MOD(l, 1, 11, 11);
+ l = FLD_MOD(l, 0x10, 10, 6);
+ l = FLD_MOD(l, 1, 5, 5);
+ l = FLD_MOD(l, 0xE, 3, 0);
+ dsi_write_reg(ix, DSI_DSIPHY_CFG8, l);
return 0;
err3:
- dsi_complexio_uninit();
+ dsi_complexio_uninit(ix);
err2:
dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dsi_clk_source(ix, DSS_SRC_DSS1_ALWON_FCLK);
err1:
- dsi_pll_uninit();
+ dsi_pll_uninit(ix);
err0:
return r;
}
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
{
+ enum omap_dsi_index ix;
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+
dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dsi_complexio_uninit();
- dsi_pll_uninit();
+ dss_select_dsi_clk_source(ix, DSS_SRC_DSS1_ALWON_FCLK);
+ dsi_complexio_uninit(ix);
+ dsi_pll_uninit(ix);
}
-static int dsi_core_init(void)
+static int dsi_core_init(enum omap_dsi_index ix)
{
/* Autoidle */
- REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
+ REG_FLD_MOD(ix, DSI_SYSCONFIG, 1, 0, 0);
/* ENWAKEUP */
- REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
+ REG_FLD_MOD(ix, DSI_SYSCONFIG, 1, 2, 2);
/* SIDLEMODE smart-idle */
- REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
+ REG_FLD_MOD(ix, DSI_SYSCONFIG, 2, 4, 3);
- _dsi_initialize_irq();
+ _dsi_initialize_irq(ix);
return 0;
}
@@ -3172,12 +3573,18 @@ static int dsi_core_init(void)
int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{
int r = 0;
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
DSSDBG("dsi_display_enable\n");
- WARN_ON(!dsi_bus_is_locked());
+ WARN_ON(!dsi_bus_is_locked(ix));
- mutex_lock(&dsi.lock);
+ mutex_lock(&p_dsi->lock);
r = omap_dss_start_device(dssdev);
if (r) {
@@ -3186,13 +3593,17 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
}
enable_clocks(1);
- dsi_enable_pll_clock(1);
+ dsi_enable_pll_clock(ix, 1);
+
+ /* DSS_PWR_DSS_DSS_CTRL */
+ if (cpu_is_omap44xx())
+ omap_writel(0x00030007, 0x4A307100);
- r = _dsi_reset();
+ r = _dsi_reset(ix);
if (r)
goto err1;
- dsi_core_init();
+ dsi_core_init(ix);
r = dsi_display_init_dispc(dssdev);
if (r)
@@ -3202,7 +3613,9 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err2;
- mutex_unlock(&dsi.lock);
+ p_dsi->use_ext_te = dssdev->phy.dsi.ext_te;
+
+ mutex_unlock(&p_dsi->lock);
return 0;
@@ -3210,10 +3623,10 @@ err2:
dsi_display_uninit_dispc(dssdev);
err1:
enable_clocks(0);
- dsi_enable_pll_clock(0);
+ dsi_enable_pll_clock(ix, 0);
omap_dss_stop_device(dssdev);
err0:
- mutex_unlock(&dsi.lock);
+ mutex_unlock(&p_dsi->lock);
DSSDBG("dsi_display_enable FAILED\n");
return r;
}
@@ -3221,28 +3634,37 @@ EXPORT_SYMBOL(omapdss_dsi_display_enable);
void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
{
+ struct dsi_struct *p_dsi;
+ enum omap_dsi_index ix;
+
+ ix = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? DSI1 : DSI2;
+ p_dsi = (ix == DSI1) ? &dsi1 : &dsi2;
+
DSSDBG("dsi_display_disable\n");
- WARN_ON(!dsi_bus_is_locked());
+ WARN_ON(!dsi_bus_is_locked(ix));
- mutex_lock(&dsi.lock);
+ mutex_lock(&p_dsi->lock);
dsi_display_uninit_dispc(dssdev);
dsi_display_uninit_dsi(dssdev);
enable_clocks(0);
- dsi_enable_pll_clock(0);
+ dsi_enable_pll_clock(ix, 0);
omap_dss_stop_device(dssdev);
- mutex_unlock(&dsi.lock);
+ mutex_unlock(&p_dsi->lock);
}
EXPORT_SYMBOL(omapdss_dsi_display_disable);
int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
{
- dsi.te_enabled = enable;
+ struct dsi_struct *p_dsi;
+ p_dsi = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? &dsi1 : &dsi2;
+
+ p_dsi->te_enabled = enable;
return 0;
}
EXPORT_SYMBOL(omapdss_dsi_enable_te);
@@ -3262,14 +3684,18 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
int dsi_init_display(struct omap_dss_device *dssdev)
{
+ struct dsi_struct *p_dsi;
+
DSSDBG("DSI init\n");
+ p_dsi = (dssdev->channel == OMAP_DSS_CHANNEL_LCD) ? &dsi1 : &dsi2;
+
/* XXX these should be figured out dynamically */
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
- dsi.vc[0].dssdev = dssdev;
- dsi.vc[1].dssdev = dssdev;
+ p_dsi->vc[0].dssdev = dssdev;
+ p_dsi->vc[1].dssdev = dssdev;
return 0;
}
@@ -3278,47 +3704,56 @@ int dsi_init(struct platform_device *pdev)
{
u32 rev;
int r;
+ enum omap_dsi_index ix = DSI1;
- spin_lock_init(&dsi.errors_lock);
- dsi.errors = 0;
+ spin_lock_init(&dsi1.errors_lock);
+ dsi1.errors = 0;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- spin_lock_init(&dsi.irq_stats_lock);
- dsi.irq_stats.last_reset = jiffies;
+ spin_lock_init(&dsi1.irq_stats_lock);
+ dsi1.irq_stats.last_reset = jiffies;
#endif
- init_completion(&dsi.bta_completion);
+ init_completion(&dsi1.bta_completion);
- mutex_init(&dsi.lock);
- sema_init(&dsi.bus_lock, 1);
+ mutex_init(&dsi1.lock);
+ sema_init(&dsi1.bus_lock, 1);
- INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
- INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
+ INIT_WORK(&dsi1.framedone_work, dsi_framedone_work_callback);
+ INIT_DELAYED_WORK_DEFERRABLE(&dsi1.framedone_timeout_work,
dsi_framedone_timeout_work_callback);
+ if (cpu_is_omap44xx()) {
+ r = request_irq(OMAP44XX_IRQ_DSS_DSI1, dsi_irq_handler,
+ 0, "OMAP DSI", (void *)0);
+ if (r)
+ goto err2;
+ }
#ifdef DSI_CATCH_MISSING_TE
- init_timer(&dsi.te_timer);
- dsi.te_timer.function = dsi_te_timeout;
- dsi.te_timer.data = 0;
+ init_timer(&dsi1.te_timer);
+ dsi1.te_timer.function = dsi_te_timeout;
+ dsi1.te_timer.data = 0;
#endif
- dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
- if (!dsi.base) {
+ dsi1.base = ioremap(DSI_BASE, DSI_SZ_REGS);
+ if (!dsi1.base) {
DSSERR("can't ioremap DSI\n");
r = -ENOMEM;
goto err1;
}
- dsi.vdds_dsi_reg = dss_get_vdds_dsi();
- if (IS_ERR(dsi.vdds_dsi_reg)) {
- iounmap(dsi.base);
- DSSERR("can't get VDDS_DSI regulator\n");
- r = PTR_ERR(dsi.vdds_dsi_reg);
- goto err2;
+ if (!cpu_is_omap44xx()) {
+ dsi1.vdds_dsi_reg = dss_get_vdds_dsi();
+ if (IS_ERR(dsi1.vdds_dsi_reg)) {
+ iounmap(dsi1.base);
+ DSSERR("can't get VDDS_DSI regulator\n");
+ r = PTR_ERR(dsi1.vdds_dsi_reg);
+ goto err2;
+ }
}
enable_clocks(1);
- rev = dsi_read_reg(DSI_REVISION);
+ rev = dsi_read_reg(ix, DSI_REVISION);
printk(KERN_INFO "OMAP DSI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -3326,15 +3761,81 @@ int dsi_init(struct platform_device *pdev)
return 0;
err2:
- iounmap(dsi.base);
+ iounmap(dsi1.base);
+ if (cpu_is_omap44xx())
+ free_irq(OMAP44XX_IRQ_DSS_DSI1, (void *)0);
+err1:
+ return r;
+}
+
+int dsi2_init(struct platform_device *pdev)
+{
+ u32 rev;
+ int r;
+ enum omap_dsi_index ix = DSI2;
+
+ spin_lock_init(&dsi2.errors_lock);
+ dsi2.errors = 0;
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock_init(&dsi2.irq_stats_lock);
+ dsi2.irq_stats.last_reset = jiffies;
+#endif
+
+ init_completion(&dsi2.bta_completion);
+
+ mutex_init(&dsi2.lock);
+ sema_init(&dsi2.bus_lock, 1);
+
+ INIT_WORK(&dsi2.framedone_work, dsi2_framedone_work_callback);
+ INIT_DELAYED_WORK_DEFERRABLE(&dsi2.framedone_timeout_work,
+ dsi2_framedone_timeout_work_callback);
+
+ r = request_irq(OMAP44XX_IRQ_DSS_DSI2, dsi_irq_handler,
+ 0, "OMAP DSI2", (void *)0);
+ if (r)
+ goto err2;
+
+#ifdef DSI_CATCH_MISSING_TE
+ init_timer(&dsi2.te_timer);
+ dsi2.te_timer.function = dsi2_te_timeout;
+ dsi2.te_timer.data = 0;
+#endif
+ dsi2.te_enabled = true;
+
+ dsi2.base = ioremap(DSI2_BASE, DSI_SZ_REGS);
+ if (!dsi2.base) {
+ DSSERR("can't ioremap DSI2\n");
+ r = -ENOMEM;
+ goto err1;
+ }
+
+ enable_clocks(1);
+
+ rev = dsi_read_reg(ix, DSI_REVISION);
+ printk(KERN_INFO "OMAP DSI2 rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ enable_clocks(0);
+
+ return 0;
+err2:
+ iounmap(dsi2.base);
+ free_irq(OMAP44XX_IRQ_DSS_DSI2, (void *)0);
err1:
return r;
}
void dsi_exit(void)
{
- iounmap(dsi.base);
+ iounmap(dsi1.base);
DSSDBG("omap_dsi_exit\n");
}
+void dsi2_exit(void)
+{
+ iounmap(dsi2.base);
+
+ DSSDBG("omap_dsi2_exit\n");
+}
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 54344184dd73..db8bc715c564 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -33,7 +33,11 @@
#include <plat/display.h>
#include "dss.h"
+#ifndef CONFIG_ARCH_OMAP4
#define DSS_BASE 0x48050000
+#else
+#define DSS_BASE 0x58000000
+#endif
#define DSS_SZ_REGS SZ_512
@@ -223,7 +227,13 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
+ if (cpu_is_omap3630())
+ seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n",
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss_clk_get_rate(DSS_CLK_FCK1));
+ else
+ seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
dpll4_ck_rate,
dpll4_ck_rate / dpll4_m4_ck_rate,
dss_clk_get_rate(DSS_CLK_FCK1));
@@ -259,12 +269,17 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
- REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
+ if (!cpu_is_omap44xx()) {
+ REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
+ } else {
+ REG_FLD_MOD(DSS_CONTROL, b, 9, 8); /* FCK_CLK_SWITCH */
+ }
dss.dispc_clk_source = clk_src;
}
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
+void dss_select_dsi_clk_source(enum omap_dsi_index ix,
+ enum dss_clk_source clk_src)
{
int b;
@@ -273,7 +288,14 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
- REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
+ if (ix == DSI1) {
+ REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
+ if (cpu_is_omap44xx())
+ REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* LCD1_CLK_SWITCH */
+ } else {
+ REG_FLD_MOD(DSS_CONTROL, b, 10, 10); /* DSI2_CLK_SWITCH */
+ REG_FLD_MOD(DSS_CONTROL, b, 12, 12); /* LCD2_CLK_SWITCH */
+ }
dss.dsi_clk_source = clk_src;
}
@@ -293,7 +315,8 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
unsigned long prate;
- if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
+ if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) ||
+ cinfo->fck_div == 0)
return -EINVAL;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
@@ -329,7 +352,10 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
if (cpu_is_omap34xx()) {
unsigned long prate;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- cinfo->fck_div = prate / (cinfo->fck / 2);
+ if (cpu_is_omap3630())
+ cinfo->fck_div = prate / (cinfo->fck);
+ else
+ cinfo->fck_div = prate / (cinfo->fck / 2);
} else {
cinfo->fck_div = 0;
}
@@ -402,10 +428,14 @@ retry:
goto found;
} else if (cpu_is_omap34xx()) {
- for (fck_div = 16; fck_div > 0; --fck_div) {
+ for (fck_div = (cpu_is_omap3630() ? 32 : 16);
+ fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- fck = prate / fck_div * 2;
+ if (cpu_is_omap3630())
+ fck = prate / fck_div;
+ else
+ fck = prate / fck_div * 2;
if (fck > DISPC_MAX_FCK)
continue;
@@ -480,8 +510,8 @@ static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
if (irqstatus & (1<<0)) /* DISPC_IRQ */
dispc_irq_handler();
#ifdef CONFIG_OMAP2_DSS_DSI
- if (irqstatus & (1<<1)) /* DSI_IRQ */
- dsi_irq_handler();
+ if (!cpu_is_omap44xx() && (irqstatus & (1<<1))) /* DSI_IRQ */
+ dsi_irq_handler(0, NULL);
#endif
return IRQ_HANDLED;
@@ -529,6 +559,13 @@ void dss_set_dac_pwrdn_bgz(bool enable)
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
}
+void dss_switch_tv_hdmi(int hdmi)
+{
+ REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* 0x1 for HDMI, 0x0 TV */
+ if (hdmi)
+ REG_FLD_MOD(DSS_CONTROL, 0, 9, 8);
+}
+
int dss_init(bool skip_init)
{
int r;
@@ -570,11 +607,16 @@ int dss_init(bool skip_init)
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
#endif
- r = request_irq(INT_24XX_DSS_IRQ,
- cpu_is_omap24xx()
- ? dss_irq_handler_omap2
- : dss_irq_handler_omap3,
- 0, "OMAP DSS", NULL);
+ if (!cpu_is_omap44xx())
+ r = request_irq(INT_24XX_DSS_IRQ,
+ cpu_is_omap24xx()
+ ? dss_irq_handler_omap2
+ : dss_irq_handler_omap3,
+ 0, "OMAP DSS", NULL);
+ else
+ r = request_irq(OMAP44XX_IRQ_DSS_DISPC,
+ dss_irq_handler_omap2,
+ 0, "OMAP DSS", NULL);
if (r < 0) {
DSSERR("omap2 dss: request_irq failed\n");
@@ -602,7 +644,8 @@ int dss_init(bool skip_init)
return 0;
fail2:
- free_irq(INT_24XX_DSS_IRQ, NULL);
+ if (!cpu_is_omap44xx())
+ free_irq(INT_24XX_DSS_IRQ, NULL);
fail1:
iounmap(dss.base);
fail0:
@@ -614,8 +657,8 @@ void dss_exit(void)
if (cpu_is_omap34xx())
clk_put(dss.dpll4_m4_ck);
- free_irq(INT_24XX_DSS_IRQ, NULL);
-
+ if (!cpu_is_omap44xx())
+ free_irq(INT_24XX_DSS_IRQ, NULL);
iounmap(dss.base);
}
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 24326a5fd292..02cd5aed5c87 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -20,9 +20,12 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <plat/display.h>
#ifndef __OMAP2_DSS_H
#define __OMAP2_DSS_H
+#include <linux/interrupt.h>
+
#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
#define DEBUG
#endif
@@ -165,6 +168,38 @@ struct dsi_clock_info {
bool use_dss2_fck;
};
+/*TODO: Move this structure to manager.c*/
+struct writeback_cache_data {
+ /* If true, cache changed, but not written to shadow registers. Set
+ * in apply(), cleared when registers written. */
+ bool dirty;
+ /* If true, shadow registers contain changed values not yet in real
+ * registers. Set when writing to shadow registers, cleared at
+ * VSYNC/EVSYNC */
+ bool shadow_dirty;
+
+ bool enabled;
+
+ u32 paddr;
+ u32 puv_addr; /* relevant for NV12 format only */
+
+ u16 width;
+ u16 height;
+ u16 input_width;
+ u16 input_height;
+
+ enum omap_color_mode color_mode;
+ enum omap_color_mode input_color_mode;
+ enum omap_writeback_capturemode capturemode;
+ enum omap_writeback_source_type source_type;
+ enum omap_writeback_source source;
+
+ enum omap_burst_size burst_size;
+ u32 fifo_low;
+ u32 fifo_high;
+
+};
+
struct seq_file;
struct platform_device;
@@ -211,11 +246,16 @@ void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
#endif
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
+/* Write back */
+void dss_init_writeback(struct platform_device *pdev);
+bool omap_dss_check_wb(struct writeback_cache_data *wb, int overlayId, int managerId);
/* DSS */
int dss_init(bool skip_init);
void dss_exit(void);
+void dss_switch_tv_hdmi(int hdmi);
+
void dss_save_context(void);
void dss_restore_context(void);
@@ -226,7 +266,8 @@ int dss_sdi_enable(void);
void dss_sdi_disable(void);
void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_dsi_clk_source(enum omap_dsi_index ix,
+ enum dss_clk_source clk_src);
enum dss_clk_source dss_get_dispc_clk_source(void);
enum dss_clk_source dss_get_dsi_clk_source(void);
@@ -249,27 +290,32 @@ int sdi_init_display(struct omap_dss_device *display);
/* DSI */
int dsi_init(struct platform_device *pdev);
void dsi_exit(void);
+int dsi2_init(struct platform_device *pdev);
+void dsi2_exit(void);
-void dsi_dump_clocks(struct seq_file *s);
-void dsi_dump_irqs(struct seq_file *s);
-void dsi_dump_regs(struct seq_file *s);
+void dsi_dump_clocks(enum omap_dsi_index ix, struct seq_file *s);
+void dsi_dump_irqs(enum omap_dsi_index ix, struct seq_file *s);
+void dsi_dump_regs(enum omap_dsi_index ix, struct seq_file *s);
void dsi_save_context(void);
void dsi_restore_context(void);
int dsi_init_display(struct omap_dss_device *display);
-void dsi_irq_handler(void);
-unsigned long dsi_get_dsi1_pll_rate(void);
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
+irqreturn_t dsi_irq_handler(int irq, void *arg);
+unsigned long dsi_get_dsi1_pll_rate(enum omap_dsi_index ix);
+int dsi_pll_set_clock_div(enum omap_dsi_index ix,
+ struct dsi_clock_info *cinfo);
+int dsi_pll_calc_clock_div_pck(enum omap_dsi_index ix,
+ bool is_tft, unsigned long req_pck,
struct dsi_clock_info *cinfo,
struct dispc_clock_info *dispc_cinfo);
int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
bool enable_hsdiv);
-void dsi_pll_uninit(void);
+void dsi_pll_uninit(enum omap_dsi_index ix);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high);
+int dsi_calc_clock_rates(struct dsi_clock_info *cinfo);
/* DPI */
int dpi_init(struct platform_device *pdev);
@@ -283,7 +329,7 @@ void dispc_dump_clocks(struct seq_file *s);
void dispc_dump_irqs(struct seq_file *s);
void dispc_dump_regs(struct seq_file *s);
void dispc_irq_handler(void);
-void dispc_fake_vsync_irq(void);
+void dispc_fake_vsync_irq(enum omap_dsi_index ix);
void dispc_save_context(void);
void dispc_restore_context(void);
@@ -295,17 +341,24 @@ void dispc_lcd_enable_signal_polarity(bool act_high);
void dispc_lcd_enable_signal(bool enable);
void dispc_pck_free_enable(bool enable);
void dispc_enable_fifohandcheck(bool enable);
+void dispc_enable_lcd_out(enum omap_channel channel, bool enable);
-void dispc_set_lcd_size(u16 width, u16 height);
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
void dispc_set_digit_size(u16 width, u16 height);
u32 dispc_get_plane_fifo_size(enum omap_plane plane);
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
void dispc_enable_fifomerge(bool enable);
void dispc_set_burst_size(enum omap_plane plane,
enum omap_burst_size burst_size);
+void dispc_set_zorder(enum omap_plane plane,
+ enum omap_overlay_zorder zorder);
+void dispc_enable_zorder(enum omap_plane plane, bool enable);
void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
+void dispc_enable_gamma_table(bool enable);
+void dispc_set_idle_mode(void);
+
void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
void dispc_set_channel_out(enum omap_plane plane,
@@ -320,18 +373,23 @@ int dispc_setup_plane(enum omap_plane plane,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror,
- u8 global_alpha);
+ u8 global_alpha, enum omap_channel channel,
+ u32 puv_addr);
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
+void dispc_enable_digit_out(bool enable);
void dispc_enable_channel(enum omap_channel channel, bool enable);
bool dispc_is_channel_enabled(enum omap_channel channel);
int dispc_enable_plane(enum omap_plane plane, bool enable);
void dispc_enable_replication(enum omap_plane plane, bool enable);
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
-void dispc_set_tft_data_lines(u8 data_lines);
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+ enum omap_parallel_interface_mode mode);
+void dispc_set_tft_data_lines(enum omap_channel channel,
+ u8 data_lines);
+void dispc_set_lcd_display_type(enum omap_channel channel,
+ enum omap_lcd_display_type type);
void dispc_set_loadmode(enum omap_dss_load_mode mode);
void dispc_set_default_color(enum omap_channel channel, u32 color);
@@ -348,18 +406,23 @@ bool dispc_trans_key_enabled(enum omap_channel ch);
bool dispc_alpha_blending_enabled(enum omap_channel ch);
bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
-void dispc_set_lcd_timings(struct omap_video_timings *timings);
+void dispc_set_lcd_timings(enum omap_channel channel,
+ struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void);
-unsigned long dispc_lclk_rate(void);
-unsigned long dispc_pclk_rate(void);
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
+unsigned long dispc_lclk_rate(enum omap_channel channel);
+unsigned long dispc_pclk_rate(enum omap_channel channel);
+void dispc_set_pol_freq(enum omap_channel channel,
+ enum omap_panel_config config, u8 acbi, u8 acb);
void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
struct dispc_clock_info *cinfo);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
-int dispc_set_clock_div(struct dispc_clock_info *cinfo);
-int dispc_get_clock_div(struct dispc_clock_info *cinfo);
-
+int dispc_set_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo);
+int dispc_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo);
+void dispc_go_wb(void);
+int dispc_setup_wb(struct writeback_cache_data *wb);
/* VENC */
int venc_init(struct platform_device *pdev);
@@ -380,6 +443,12 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
unsigned long rfbi_get_max_tx_rate(void);
int rfbi_init_display(struct omap_dss_device *display);
+#ifdef CONFIG_OMAP2_DSS_HDMI
+int hdmi_init(struct platform_device *pdev, int code, int mode);
+void hdmi_exit(void);
+void hdmi_dump_regs(struct seq_file *s);
+int hdmi_init_display(struct omap_dss_device *display);
+#endif
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
new file mode 100644
index 000000000000..6a248cce7ec8
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -0,0 +1,1373 @@
+/*
+ * linux/drivers/video/omap2/dss/hdmi.c
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Author: Yong Zhi
+ *
+ * HDMI settings from TI's DSS driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ * History:
+ * Mythripk <mythripk@ti.com> Apr 2010 Modified for EDID reading and adding OMAP
+ * related timing
+ * May 2010 Added support of Hot Plug Detect
+ *
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <plat/display.h>
+#include <plat/cpu.h>
+#include <plat/hdmi_lib.h>
+#include <plat/gpio.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+#define HDMI_PLLCTRL 0x58006200
+#define HDMI_PHY 0x58006300
+
+u16 current_descriptor_addrs;
+u8 edid[HDMI_EDID_MAX_LENGTH] = {0};
+u8 edid_set = 0;
+u8 header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
+u8 hpd_mode = 0;
+/* PLL */
+#define PLLCTRL_PLL_CONTROL 0x0ul
+#define PLLCTRL_PLL_STATUS 0x4ul
+#define PLLCTRL_PLL_GO 0x8ul
+#define PLLCTRL_CFG1 0xCul
+#define PLLCTRL_CFG2 0x10ul
+#define PLLCTRL_CFG3 0x14ul
+#define PLLCTRL_CFG4 0x20ul
+
+/* HDMI PHY */
+#define HDMI_TXPHY_TX_CTRL 0x0ul
+#define HDMI_TXPHY_DIGITAL_CTRL 0x4ul
+#define HDMI_TXPHY_POWER_CTRL 0x8ul
+#define HDMI_TXPHY_PAD_CFG_CTRL 0xCul
+
+/*This is the structure which has all supported timing values that OMAP4 supports*/
+struct omap_video_timings all_timings_direct[31] = { {640, 480, 25200, 96, 16, 48, 2, 10, 33},
+ {1280, 720, 74250, 40, 440, 220, 5, 5, 20},
+ {1280, 720, 74250, 40, 110, 220, 5, 5, 20},
+ {720, 480, 27000, 62, 16, 60, 6, 9, 30},
+ {2880, 576, 108000, 256, 48, 272, 5, 5, 39},
+ {1440, 480, 27000, 124, 38, 114, 3, 4, 15},
+ {1440, 576, 27000, 126, 24, 138, 3, 2, 19},
+ {1920, 1080, 74250, 44, 528, 148, 2, 5, 15},
+ {1920, 1080, 74250, 44, 88, 148, 2, 5, 15},
+ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36},
+ {720, 576, 27000, 64, 12, 68, 5, 5, 39},
+ {1440, 576, 54000, 128, 24, 136, 5, 5, 39},
+ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36},
+ {2880, 480, 108000, 248, 64, 240, 6, 9, 30},
+ /*Vesa frome here*/
+ {640, 480, 25175, 96, 16, 48, 2 , 11, 31},
+ {800, 600, 40000, 128, 40, 88, 4 , 1, 23},
+ {848, 480, 33750, 112, 16, 112, 8 , 6, 23},
+ {1280, 768, 71000, 128, 64, 192, 7 , 3, 20},
+ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, {1360, 768, 85500, 112, 64, 256, 6 , 3, 18},
+ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36},
+ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38},
+ {1024, 768, 65000, 136, 24, 160, 6, 3, 29},
+ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32},
+ {1440, 900, 106500, 152, 80, 232, 6, 3, 25},
+ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30},
+ {1366, 768, 85500, 143, 70, 213, 3, 3, 24},
+ {1920, 1080, 148500, 44, 88, 80, 5, 4, 36},
+ {1280, 768, 68250, 32, 48, 80, 7, 3, 12},
+ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, {1680, 1050, 119000, 32, 48, 80, 6, 3, 21} } ;
+
+/*This is a static Mapping array which maps the timing values with corresponding CEA / VESA code*/
+int code_index[31] = {1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35,
+ /* <--14 CEA 17--> vesa*/
+ 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
+ 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39};
+
+/*This is revere static mapping which maps the CEA / VESA code to the corresponding timing values*/
+int code_cea[39] = {-1, 0, 3, 3, 2, 8, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, 9,
+ 10, 10, 1, 7, 6, 6 , -1, -1, -1, -1, -1, -1, 11, 11,
+ 12, -1, -1, -1, 13, 13, 4, 4};
+
+int code_vesa[83] = {-1, -1, -1, -1, 14, -1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
+ -1, 22, -1, -1, -1, -1, -1, 28, 17, -1, -1, -1, -1, 18,
+ -1, -1, -1, 20, -1, -1, 21, -1, -1, -1, 19, -1, 29, 23,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 30, 25, -1, -1, -1, -1, -1, -1, -1 , -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27};
+
+
+
+static struct {
+ void __iomem *base_phy;
+ void __iomem *base_pll;
+ struct mutex lock;
+ int code;
+ int mode;
+ HDMI_Timing_t ti;
+} hdmi;
+
+static struct hdmi_cm {
+ int code;
+ int mode;
+};
+struct omap_video_timings edid_timings;
+
+static inline void hdmi_write_reg(u32 base, u16 idx, u32 val)
+{
+ void __iomem *b;
+
+ switch (base) {
+ case HDMI_PHY:
+ b = hdmi.base_phy;
+ break;
+ case HDMI_PLLCTRL:
+ b = hdmi.base_pll;
+ break;
+ default:
+ BUG();
+ }
+ __raw_writel(val, b + idx);
+ /* DBG("write = 0x%x idx =0x%x\r\n", val, idx); */
+}
+
+static inline u32 hdmi_read_reg(u32 base, u16 idx)
+{
+ void __iomem *b;
+ u32 l;
+
+ switch (base) {
+ case HDMI_PHY:
+ b = hdmi.base_phy;
+ break;
+ case HDMI_PLLCTRL:
+ b = hdmi.base_pll;
+ break;
+ default:
+ BUG();
+ }
+ l = __raw_readl(b + idx);
+
+ /* DBG("addr = 0x%p rd = 0x%x idx = 0x%x\r\n", (b+idx), l, idx); */
+ return l;
+}
+
+#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
+#define FLD_MOD(orig, val, start, end) \
+ (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
+
+#define REG_FLD_MOD(b, i, v, s, e) \
+ hdmi_write_reg(b, i, FLD_MOD(hdmi_read_reg(b, i), v, s, e))
+
+/*
+ * refclk = (sys_clk/(highfreq+1))/(n+1)
+ * so refclk = 38.4/2/(n+1) = 19.2/(n+1)
+ * choose n = 15, makes refclk = 1.2
+ *
+ * m = tclk/cpf*refclk = tclk/2*1.2
+ *
+ * for clkin = 38.2/2 = 192
+ * phy = 2520
+ *
+ * m = 2520*16/2* 192 = 105;
+ *
+ * for clkin = 38.4
+ * phy = 2520
+ *
+ */
+
+#define CPF 2
+
+struct hdmi_pll_info {
+ u16 regn;
+ u16 regm;
+ u32 regmf;
+ u16 regm4; /* M4_CLOCK_DIV */
+ u16 regm2;
+ u16 regsd;
+ u16 dcofreq;
+};
+
+static void compute_pll(int clkin, int phy,
+ int n, struct hdmi_pll_info *pi)
+{
+ int refclk;
+ u32 temp, mf;
+
+ if (clkin > 3200) /* 32 mHz */
+ refclk = clkin / (2 * (n + 1));
+ else
+ refclk = clkin / (n + 1);
+
+ temp = phy * 100/(CPF * refclk);
+
+ pi->regn = n;
+ pi->regm = temp/100;
+ pi->regm2 = 1;
+
+ mf = (phy - pi->regm * CPF * refclk) * 262144;
+ pi->regmf = mf/(CPF * refclk);
+
+ if (phy > 1000 * 100) {
+ pi->regm4 = phy / 10000;
+ pi->dcofreq = 1;
+ pi->regsd = ((pi->regm * 384)/((n + 1) * 250) + 5)/10;
+ } else {
+ pi->regm4 = 1;
+ pi->dcofreq = 0;
+ pi->regsd = 0;
+ }
+
+ DSSDBG("M = %d Mf = %d, m4= %d\n", pi->regm, pi->regmf, pi->regm4);
+ DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+}
+
+static int hdmi_pll_init(int refsel, int dcofreq, struct hdmi_pll_info *fmt, u16 sd)
+{
+ u32 r;
+ unsigned t = 500000;
+ u32 pll = HDMI_PLLCTRL;
+
+ /* PLL start always use manual mode */
+ REG_FLD_MOD(pll, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
+
+ r = hdmi_read_reg(pll, PLLCTRL_CFG1);
+ r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1__PLL_REGM */
+ r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1__PLL_REGN */
+ r = FLD_MOD(r, fmt->regm4, 25, 21); /* M4_CLOCK_DIV */
+
+ hdmi_write_reg(pll, PLLCTRL_CFG1, r);
+
+ r = hdmi_read_reg(pll, PLLCTRL_CFG2);
+
+ /* SYS w/o divide by 2 [22:21] = donot care [11:11] = 0x0 */
+ /* SYS divide by 2 [22:21] = 0x3 [11:11] = 0x1 */
+ /* PCLK, REF1 or REF2 [22:21] = 0x0, 0x 1 or 0x2 [11:11] = 0x1 */
+ r = FLD_MOD(r, 0x0, 11, 11); /* PLL_CLKSEL 1: PLL 0: SYS*/
+ r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+ r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
+ r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
+ r = FLD_MOD(r, 0x1, 20, 20); /* HSDIVBYPASS assert during locking */
+ r = FLD_MOD(r, refsel, 22, 21); /* REFSEL */
+ /* DPLL3 used by DISPC or HDMI itself*/
+ r = FLD_MOD(r, 0x0, 17, 17); /* M4_CLOCK_PWDN */
+ r = FLD_MOD(r, 0x1, 16, 16); /* M4_CLOCK_EN */
+
+ if (dcofreq) {
+ /* divider programming for 1080p */
+ REG_FLD_MOD(pll, PLLCTRL_CFG3, sd, 17, 10);
+ r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
+ } else
+ r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
+
+ hdmi_write_reg(pll, PLLCTRL_CFG2, r);
+
+ r = hdmi_read_reg(pll, PLLCTRL_CFG4);
+ r = FLD_MOD(r, 0, 24, 18); /* todo: M2 */
+ r = FLD_MOD(r, fmt->regmf, 17, 0);
+
+ /* go now */
+ REG_FLD_MOD(pll, PLLCTRL_PLL_GO, 0x1ul, 0, 0);
+
+ /* wait for bit change */
+ while (FLD_GET(hdmi_read_reg(pll, PLLCTRL_PLL_GO), 0, 0))
+
+ /* Wait till the lock bit is set */
+ /* read PLL status */
+ while (0 == FLD_GET(hdmi_read_reg(pll, PLLCTRL_PLL_STATUS), 1, 1)) {
+ udelay(1);
+ if (!--t) {
+ printk(KERN_WARNING "HDMI: cannot lock PLL\n");
+ DSSDBG("CFG1 0x%x\n", hdmi_read_reg(pll, PLLCTRL_CFG1));
+ DSSDBG("CFG2 0x%x\n", hdmi_read_reg(pll, PLLCTRL_CFG2));
+ DSSDBG("CFG4 0x%x\n", hdmi_read_reg(pll, PLLCTRL_CFG4));
+ return -EIO;
+ }
+ }
+
+ DSSDBG("PLL locked!\n");
+
+ r = hdmi_read_reg(pll, PLLCTRL_CFG2);
+ r = FLD_MOD(r, 0, 0, 0); /* PLL_IDLE */
+ r = FLD_MOD(r, 0, 5, 5); /* PLL_PLLLPMODE */
+ r = FLD_MOD(r, 0, 6, 6); /* PLL_LOWCURRSTBY */
+ r = FLD_MOD(r, 0, 8, 8); /* PLL_DRIFTGUARDEN */
+ r = FLD_MOD(r, 0, 10, 9); /* PLL_LOCKSEL */
+ r = FLD_MOD(r, 1, 13, 13); /* PLL_REFEN */
+ r = FLD_MOD(r, 1, 14, 14); /* PHY_CLKINEN */
+ r = FLD_MOD(r, 0, 15, 15); /* BYPASSEN */
+ r = FLD_MOD(r, 0, 20, 20); /* HSDIVBYPASS */
+ hdmi_write_reg(pll, PLLCTRL_CFG2, r);
+
+ return 0;
+}
+
+static int hdmi_pll_reset(void)
+{
+ int t = 0;
+
+ /* SYSREEST controled by power FSM*/
+ REG_FLD_MOD(HDMI_PLLCTRL, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+
+ /* READ 0x0 reset is in progress */
+ while (!FLD_GET(hdmi_read_reg(HDMI_PLLCTRL,
+ PLLCTRL_PLL_STATUS), 0, 0)) {
+ udelay(1);
+ if (t++ > 1000) {
+ ERR("Failed to sysrest PLL\n");
+ return -ENODEV;
+ }
+ }
+ return 0;
+}
+
+int hdmi_pll_program(struct hdmi_pll_info *fmt)
+{
+ u32 r;
+ int refsel;
+
+ HDMI_PllPwr_t PllPwrWaitParam;
+
+ /* wait for wrapper rest */
+ HDMI_W1_SetWaitSoftReset();
+
+ /* power off PLL */
+ PllPwrWaitParam = HDMI_PLLPWRCMD_ALLOFF;
+ r = HDMI_W1_SetWaitPllPwrState(HDMI_WP,
+ PllPwrWaitParam);
+ if (r)
+ return r;
+
+ /* power on PLL */
+ PllPwrWaitParam = HDMI_PLLPWRCMD_BOTHON_ALLCLKS;
+ r = HDMI_W1_SetWaitPllPwrState(HDMI_WP,
+ PllPwrWaitParam);
+ if (r)
+ return r;
+
+ hdmi_pll_reset();
+
+ refsel = 0x3; /* select SYSCLK reference */
+
+ r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd);
+
+ return r;
+}
+
+/* double check the order */
+static int hdmi_phy_init(u32 w1,
+ u32 phy)
+{
+ u32 count;
+ int r;
+
+ /* wait till PHY_PWR_STATUS=LDOON */
+ /* HDMI_PHYPWRCMD_LDOON = 1 */
+ r = HDMI_W1_SetWaitPhyPwrState(w1, 1);
+ if (r)
+ return r;
+
+ /* wait till PHY_PWR_STATUS=TXON */
+ r = HDMI_W1_SetWaitPhyPwrState(w1, 2);
+ if (r)
+ return r;
+
+ /* read address 0 in order to get the SCPreset done completed */
+ /* Dummy access performed to solve resetdone issue */
+ hdmi_read_reg(phy, HDMI_TXPHY_TX_CTRL);
+
+ /* write to phy address 0 to configure the clock */
+ /* use HFBITCLK write HDMI_TXPHY_TX_CONTROL__FREQOUT field */
+ REG_FLD_MOD(phy, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+
+ /* write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+ hdmi_write_reg(phy, HDMI_TXPHY_DIGITAL_CTRL,
+ 0xF0000000);
+
+ /* setup max LDO voltage */
+ REG_FLD_MOD(phy, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+ /* write to phy address 3 to change the polarity control */
+ REG_FLD_MOD(phy, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+
+ count = 0;
+ while (count++ < 1000)
+ ;
+
+ return 0;
+}
+
+static int hdmi_phy_off(u32 name)
+{
+ int r = 0;
+ u32 count;
+
+ /* wait till PHY_PWR_STATUS=OFF */
+ /* HDMI_PHYPWRCMD_OFF = 0 */
+ r = HDMI_W1_SetWaitPhyPwrState(name, 0);
+ if (r)
+ return r;
+
+ count = 0;
+ while (count++ < 200)
+ ;
+
+ return 0;
+}
+
+/* driver */
+static int hdmi_panel_probe(struct omap_dss_device *dssdev)
+{
+ int code;
+ DSSDBG("ENTER hdmi_panel_probe()\n");
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT |
+ OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
+
+ if (hdmi.mode == 0)
+ code = code_vesa[hdmi.code];
+ else
+ code = code_cea[hdmi.code];
+ if (code == -1) {
+ code = 9;
+ hdmi.code = 16;
+ hdmi.mode = 1;
+ }
+
+ dssdev->panel.timings = all_timings_direct[code];
+ DSSDBG("hdmi_panel_probe x_res= %d y_res = %d", dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+
+ return 0;
+}
+
+static void hdmi_panel_remove(struct omap_dss_device *dssdev)
+{
+
+}
+
+static int hdmi_panel_enable(struct omap_dss_device *dssdev)
+{
+ hdmi_enable_display(dssdev);
+ return 0;
+}
+
+static void hdmi_panel_disable(struct omap_dss_device *dssdev)
+{
+ hdmi_disable_display(dssdev);
+}
+
+static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
+{
+ hdmi_display_suspend(dssdev);
+ return 0;
+}
+
+static int hdmi_panel_resume(struct omap_dss_device *dssdev)
+{
+ hdmi_display_resume(dssdev);
+ return 0;
+}
+
+static void hdmi_enable_clocks(int enable)
+{
+ if (enable)
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
+ DSS_CLK_96M);
+ else
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
+ DSS_CLK_96M);
+}
+
+static struct omap_dss_driver hdmi_driver = {
+ .probe = hdmi_panel_probe,
+ .remove = hdmi_panel_remove,
+
+ .enable = hdmi_panel_enable,
+ .disable = hdmi_panel_disable,
+ .suspend = hdmi_panel_suspend,
+ .resume = hdmi_panel_resume,
+ .get_timings = hdmi_get_timings,
+ .set_timings = hdmi_set_timings,
+ .check_timings = hdmi_check_timings,
+ .get_edid = hdmi_get_edid,
+ .set_custom_edid_timing_code = hdmi_set_custom_edid_timing_code,
+ .hpd_enable = hdmi_enable_hpd,
+ .driver = {
+ .name = "hdmi_panel",
+ .owner = THIS_MODULE,
+ },
+};
+/* driver end */
+
+int hdmi_init(struct platform_device *pdev, int code, int mode)
+{
+ int r = 0;
+ DSSDBG("Enter hdmi_init()\n");
+
+ mutex_init(&hdmi.lock);
+
+ hdmi.base_pll = ioremap(HDMI_PLLCTRL, 64);
+ if (!hdmi.base_pll) {
+ ERR("can't ioremap pll\n");
+ return -ENOMEM;
+ }
+ hdmi.base_phy = ioremap(HDMI_PHY, 64);
+
+ if (!hdmi.base_phy) {
+ ERR("can't ioremap phy\n");
+ return -ENOMEM;
+ }
+ hdmi.code = code;
+ hdmi.mode = mode;
+ DSSDBG("%d code %d mode", hdmi.code, hdmi.mode);
+ hdmi_enable_clocks(1);
+
+ hdmi_lib_init();
+
+ hdmi_enable_clocks(0);
+ r = request_irq(OMAP44XX_IRQ_DSS_HDMI, hdmi_irq_handler,
+ 0, "OMAP HDMI", (void *)0);
+
+
+ return omap_dss_register_driver(&hdmi_driver);
+
+}
+
+void hdmi_exit(void)
+{
+ hdmi_lib_exit();
+ free_irq(OMAP44XX_IRQ_DSS_HDMI, NULL);
+ iounmap(hdmi.base_pll);
+ iounmap(hdmi.base_phy);
+}
+
+static int hdmi_power_on(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ int code = 0;
+ struct omap_video_timings *p;
+ struct hdmi_pll_info pll_data;
+
+ int clkin, n, phy;
+
+ if (hdmi.mode == 0)
+ code = code_vesa[hdmi.code];
+ else
+ code = code_cea[hdmi.code];
+ if (code == -1) {
+ code = 9;
+ hdmi.code = 16;
+ hdmi.mode = 1;
+ }
+
+ dssdev->panel.timings = all_timings_direct[code];
+ DSSDBG("hdmi_panel_probe x_res= %d y_res = %d", dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+
+ hdmi_enable_clocks(1);
+
+ p = &dssdev->panel.timings;
+
+ r = hdmi_read_edid(p);
+ if (r) {
+ r = -EIO;
+ goto err;
+ }
+
+ clkin = 3840; /* 38.4 mHz */
+ n = 15; /* this is a constant for our math */
+ phy = p->pixel_clock;
+ compute_pll(clkin, phy, n, &pll_data);
+
+ HDMI_W1_StopVideoFrame(HDMI_WP);
+
+ dispc_enable_digit_out(0);
+
+ /* config the PLL and PHY first */
+ r = hdmi_pll_program(&pll_data);
+ if (r) {
+ DSSERR("Failed to lock PLL\n");
+ r = -EIO;
+ goto err;
+ }
+
+ r = hdmi_phy_init(HDMI_WP, HDMI_PHY);
+ if (r) {
+ DSSERR("Failed to start PHY\n");
+ r = -EIO;
+ goto err;
+ }
+
+ DSS_HDMI_CONFIG(hdmi.ti, hdmi.code, hdmi.mode);
+
+ /* these settings are independent of overlays */
+ dss_switch_tv_hdmi(1);
+
+ /* bypass TV gamma table*/
+ dispc_enable_gamma_table(0);
+
+ /* do not fall into any sort of idle */
+ dispc_set_idle_mode();
+
+ /* tv size */
+ dispc_set_digit_size(dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+
+ HDMI_W1_StartVideoFrame(HDMI_WP);
+
+ dispc_enable_digit_out(1);
+
+ return 0;
+err:
+ return r;
+}
+
+int hdmi_min_enable(void)
+{
+ int r;
+ DSSDBG("hdmi_min_enable");
+ r = hdmi_phy_init(HDMI_WP, HDMI_PHY);
+ if (r) {
+ DSSERR("Failed to start PHY\n");
+ }
+ DSS_HDMI_CONFIG(hdmi.ti, hdmi.code, hdmi.mode);
+ return 0;
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *arg)
+{
+ int r = 0;
+ struct omap_dss_device *dssdev = NULL;
+ const char *buf = "hdmi";
+ int match(struct omap_dss_device *dssdev2 , void *data)
+ {
+ const char *str = data;
+ return sysfs_streq(dssdev2->name , str);
+ }
+ dssdev = omap_dss_find_device((void *)buf , match);
+ DSSDBG("found hdmi handle %s" , dssdev->name);
+ HDMI_W1_HPD_handler(&r);
+ DSSDBG("r = %d", r);
+
+ if ((r == 4 || r == 2) && (hpd_mode == 1)) {
+ hdmi_phy_off(HDMI_WP);
+ hdmi_enable_clocks(1);
+ hdmi_power_on(dssdev);
+ mdelay(1000);
+ printk(KERN_INFO "Display enabled");
+ }
+ if (r == 1 || r == 4) {
+ hpd_mode = 0;
+ }
+ if ((r == 3) && (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
+ printk(KERN_INFO "Display disabled");
+ hdmi_power_off(dssdev);
+ hpd_mode = 1;
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ hdmi_min_enable();
+ }
+
+ return IRQ_HANDLED;
+
+}
+
+static void hdmi_power_off(struct omap_dss_device *dssdev)
+{
+ HDMI_W1_StopVideoFrame(HDMI_WP);
+
+ dispc_enable_digit_out(0);
+
+ hdmi_phy_off(HDMI_WP);
+
+ HDMI_W1_SetWaitPllPwrState(HDMI_WP, HDMI_PLLPWRCMD_ALLOFF);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ edid_set = 0;
+ hdmi_enable_clocks(0);
+
+ /* reset to default */
+
+}
+
+static int hdmi_enable_display(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ DSSDBG("ENTER hdmi_enable_display()\n");
+
+ mutex_lock(&hdmi.lock);
+
+ /* the tv overlay manager is shared*/
+ r = omap_dss_start_device(dssdev);
+ if (r) {
+ DSSERR("failed to start device\n");
+ goto err;
+ }
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ free_irq(OMAP44XX_IRQ_DSS_HDMI, NULL);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+ omap_writel(0x01180118, 0x4A100098);
+ /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+ omap_writel(0x01180118 , 0x4A10009C);
+ /* CONTROL_HDMI_TX_PHY */
+ omap_writel(0x10000000, 0x4A100610);
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+
+ r = hdmi_power_on(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err;
+ }
+ r = request_irq(OMAP44XX_IRQ_DSS_HDMI, hdmi_irq_handler,
+ 0, "OMAP HDMI", (void *)0);
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+
+}
+
+static int hdmi_enable_hpd(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ DSSDBG("ENTER hdmi_enable_hpd()\n");
+
+ mutex_lock(&hdmi.lock);
+
+ /* the tv overlay manager is shared*/
+ r = omap_dss_start_device(dssdev);
+ if (r) {
+ DSSERR("failed to start device\n");
+ goto err;
+ }
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+ omap_writel(0x01180118, 0x4A100098);
+ /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+ omap_writel(0x01180118 , 0x4A10009C);
+ /* CONTROL_HDMI_TX_PHY */
+ omap_writel(0x10000000, 0x4A100610);
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+
+ hpd_mode = 1;
+ r = hdmi_min_enable();
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err;
+ }
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+
+}
+
+static void hdmi_disable_display(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter hdmi_disable_display()\n");
+
+ mutex_lock(&hdmi.lock);
+ if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
+ goto end;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
+ /* suspended is the same as disabled with venc */
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ goto end;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ omap_dss_stop_device(dssdev);
+
+ hdmi_power_off(dssdev);
+
+ hdmi.code = 16;
+ hdmi.mode = 1 ; /*setting to default only in case of disable and not suspend*/
+end:
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_display_suspend(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("hdmi_display_suspend\n");
+ mutex_lock(&hdmi.lock);
+ if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
+ goto end;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
+ goto end;
+
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+ omap_dss_stop_device(dssdev);
+
+ hdmi_power_off(dssdev);
+end:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static int hdmi_display_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("hdmi_display_resume\n");
+ mutex_lock(&hdmi.lock);
+
+ /* the tv overlay manager is shared*/
+ r = omap_dss_start_device(dssdev);
+ if (r) {
+ DSSERR("failed to start device\n");
+ goto err;
+ }
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+ omap_writel(0x01180118, 0x4A100098);
+ /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+ omap_writel(0x01180118 , 0x4A10009C);
+ /* CONTROL_HDMI_TX_PHY */
+ omap_writel(0x10000000, 0x4A100610);
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+
+ r = hdmi_power_on(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err;
+ }
+
+err:
+ mutex_unlock(&hdmi.lock);
+
+ return r;
+}
+
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ DSSDBG("hdmi_set_timings\n");
+
+ dssdev->panel.timings = *timings;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ /* turn the hdmi off and on to get new timings to use */
+ hdmi_disable_display(dssdev);
+ hdmi_enable_display(dssdev);
+ }
+}
+
+static void hdmi_set_custom_edid_timing_code(struct omap_dss_device *dssdev, int code , int mode)
+{
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ /* turn the hdmi off and on to get new timings to use */
+ hdmi_disable_display(dssdev);
+ hdmi.code = code;
+ hdmi.mode = mode;
+ hdmi_enable_display(dssdev);
+ }
+}
+
+static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
+{
+ int i = 0, code = -1;
+ struct omap_video_timings temp;
+ struct hdmi_cm cm = {-1};
+ DSSDBG("hdmi_get_code");
+
+ for (i = 0; i < 31; i++) {
+ temp = all_timings_direct[i];
+
+ if (!memcmp(&temp, timing, sizeof(struct omap_video_timings))) {
+
+ code = i;
+ cm.code = code_index[i];
+ if (code < 14)
+ cm.mode = 1;
+ else
+ cm.mode = 0;
+ printk(KERN_INFO "Hdmi_code = %d mode = %d ", cm.code, cm.mode);
+ printk(KERN_INFO "Timing Info "
+ "pixel_clk = %d\n"
+ "Xresolution =%d\n"
+ "yresolution =%d\n"
+ "hfp = %d\n"
+ "hsw = %d\n"
+ "hbp = %d\n"
+ "vfp = %d\n"
+ "vsw = %d\n"
+ "vbp = %d\n",
+ temp.pixel_clock,
+ temp.x_res,
+ temp.y_res,
+ temp.hfp,
+ temp.hsw,
+ temp.hbp,
+ temp.vfp,
+ temp.vsw,
+ temp.vbp);
+ break;
+ }
+
+ }
+ return cm;
+}
+
+static void hdmi_get_edid(struct omap_dss_device *dssdev)
+{
+ u8 i = 0, flag = 0;
+ int count, offset, effective_addrs;
+ if (edid_set != 1) {
+ printk(KERN_WARNING "Display doesnt seem to be enabled invalid read\n");
+ if (HDMI_CORE_DDC_READEDID(HDMI_CORE_SYS, edid) != 0) {
+ printk(KERN_WARNING "HDMI failed to read E-EDID\n");
+ }
+ for (i = 0x00; i < 0x08; i++) {
+ if (edid[i] == header[i])
+ continue;
+ else {
+ flag = 1;
+ break;
+ }
+ }
+ if (flag == 0)
+ edid_set = 1;
+ }
+
+ mdelay(1000);
+
+ printk("\nHeader:\n");
+ for (i = 0x00; i < 0x08; i++)
+ printk("%02x ", edid[i]);
+ printk("\nVendor & Product:\n");
+ for (i = 0x08; i < 0x12; i++)
+ printk("%02x ", edid[i]);
+ printk("\nEDID Structure:\n");
+ for (i = 0x12; i < 0x14; i++)
+ printk("%02x ", edid[i]);
+ printk("\nBasic Display Parameter:\n");
+ for (i = 0x14; i < 0x19; i++)
+ printk("%02x ", edid[i]);
+ printk("\nColor Characteristics:\n");
+ for (i = 0x19; i < 0x23; i++)
+ printk("%02x ", edid[i]);
+ printk("\nEstablished timings:\n");
+ for (i = 0x23; i < 0x26; i++)
+ printk("%02x ", edid[i]);
+ printk("\nStandard timings:\n");
+ for (i = 0x26; i < 0x36; i++)
+ printk("%02x ", edid[i]);
+
+ for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+ current_descriptor_addrs =
+ EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ show_horz_vert_timing_info(edid);
+ }
+ if (edid[0x7e] != 0x00) {
+ offset = edid[EDID_DESCRIPTOR_BLOCK1_ADDRESS + 2];
+ printk("\n offset %x\n", offset);
+ if (offset != 0) {
+ effective_addrs = EDID_DESCRIPTOR_BLOCK1_ADDRESS
+ + offset;
+ /*to determine the number of descriptor blocks */
+ for (count = 0;
+ count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+ count++) {
+ current_descriptor_addrs = effective_addrs +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ show_horz_vert_timing_info(edid);
+ }
+ }
+
+
+ }
+ hdmi_get_image_format();
+ hdmi_get_audio_format();
+
+}
+void show_horz_vert_timing_info(u8 *edid)
+{
+ struct omap_video_timings timings_value;
+
+ printk(KERN_INFO
+ "EDID DTD block address = 0x%x\n",
+ current_descriptor_addrs
+ );
+ /*X and Y resolution */
+ timings_value.x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
+ edid[current_descriptor_addrs + 2]);
+ timings_value.y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
+ edid[current_descriptor_addrs + 5]);
+ timings_value.pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
+ edid[current_descriptor_addrs]);
+
+ timings_value.pixel_clock = 10 * timings_value.pixel_clock;
+
+ /*HORIZONTAL FRONT PORCH */
+ timings_value.hfp = edid[current_descriptor_addrs + 8];
+ /*HORIZONTAL SYNC WIDTH */
+ timings_value.hsw = edid[current_descriptor_addrs + 9];
+ /*HORIZONTAL BACK PORCH */
+ timings_value.hbp = (((edid[current_descriptor_addrs + 4]
+ & 0x0F) << 8) |
+ edid[current_descriptor_addrs + 3]) -
+ (timings_value.hfp + timings_value.hsw);
+ /*VERTICAL FRONT PORCH */
+ timings_value.vfp = ((edid[current_descriptor_addrs + 10] &
+ 0xF0) >> 4);
+ /*VERTICAL SYNC WIDTH */
+ timings_value.vsw = (edid[current_descriptor_addrs + 10] &
+ 0x0F);
+ /*VERTICAL BACK PORCH */
+ timings_value.vbp = (((edid[current_descriptor_addrs + 7] &
+ 0x0F) << 8) |
+ edid[current_descriptor_addrs + 6]) -
+ (timings_value.vfp + timings_value.vsw);
+
+ hdmi_get_code(&timings_value);
+
+}
+
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ DSSDBG("hdmi_check_timings\n");
+
+ if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)) == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+ DSSDBG("init_display\n");
+
+ return 0;
+}
+
+static int hdmi_read_edid(struct omap_video_timings *dp)
+{
+ int r = 0, i = 0 , flag = 0 , ret;
+
+ u16 horizontal_res;
+ u16 vertical_res;
+ u16 pixel_clk;
+ struct hdmi_cm cm;
+ struct omap_video_timings *tp;
+
+ memset(edid, 0, HDMI_EDID_MAX_LENGTH);
+ tp = dp;
+
+ if (edid_set != 1) {
+ ret = HDMI_CORE_DDC_READEDID(HDMI_CORE_SYS, edid);
+ }
+ if (ret != 0) {
+ printk(KERN_WARNING "HDMI failed to read E-EDID\n");
+
+ } else {
+ for (i = 0x00; i < 0x08; i++) {
+ if (edid[i] == header[i])
+ continue;
+ else {
+ flag = 1;
+ break;
+ }
+ }
+ if (flag == 0)
+ edid_set = 1;
+ edid_timings.pixel_clock = dp->pixel_clock;
+ edid_timings.x_res = dp->x_res;
+ edid_timings.y_res = dp->y_res;
+ /* search for timings of default resolution */
+ if (get_edid_timing_data(edid, &pixel_clk,
+ &horizontal_res, &vertical_res)) {
+ dp->pixel_clock = pixel_clk * 10; /* be careful */
+ tp = &edid_timings;
+ } else {
+ edid_timings.pixel_clock =
+ all_timings_direct[2].pixel_clock;
+ edid_timings.x_res = all_timings_direct[2].x_res;
+ edid_timings.y_res = all_timings_direct[2].y_res;
+ if (get_edid_timing_data(edid,
+ &pixel_clk, &horizontal_res,
+ &vertical_res)) {
+ dp->pixel_clock = pixel_clk * 10;
+ dp->x_res = horizontal_res;
+ dp->y_res = vertical_res;
+ tp = &edid_timings;
+
+ }
+ }
+
+ }
+ cm = hdmi_get_code(tp);
+ hdmi.code = cm.code;
+ hdmi.mode = cm.mode;
+ hdmi.ti.pixelPerLine = tp->x_res;
+ hdmi.ti.linePerPanel = tp->y_res;
+ hdmi.ti.horizontalBackPorch = tp->hbp;
+ hdmi.ti.horizontalFrontPorch = tp->hfp;
+ hdmi.ti.horizontalSyncPulse = tp->hsw;
+ hdmi.ti.verticalBackPorch = tp->vbp;
+ hdmi.ti.verticalFrontPorch = tp->vfp;
+ hdmi.ti.verticalSyncPulse = tp->vsw;
+
+ return r;
+}
+
+u16 current_descriptor_addrs;
+
+void get_horz_vert_timing_info(u8 *edid)
+{
+ /*HORIZONTAL FRONT PORCH */
+ edid_timings.hfp = edid[current_descriptor_addrs + 8];
+ /*HORIZONTAL SYNC WIDTH */
+ edid_timings.hsw = edid[current_descriptor_addrs + 9];
+ /*HORIZONTAL BACK PORCH */
+ edid_timings.hbp = (((edid[current_descriptor_addrs + 4]
+ & 0x0F) << 8) |
+ edid[current_descriptor_addrs + 3]) -
+ (edid_timings.hfp + edid_timings.hsw);
+ /*VERTICAL FRONT PORCH */
+ edid_timings.vfp = ((edid[current_descriptor_addrs + 10] &
+ 0xF0) >> 4);
+ /*VERTICAL SYNC WIDTH */
+ edid_timings.vsw = (edid[current_descriptor_addrs + 10] &
+ 0x0F);
+ /*VERTICAL BACK PORCH */
+ edid_timings.vbp = (((edid[current_descriptor_addrs + 7] &
+ 0x0F) << 8) |
+ edid[current_descriptor_addrs + 6]) -
+ (edid_timings.vfp + edid_timings.vsw);
+
+ DSSDBG(KERN_INFO "hfp = %d\n"
+ "hsw = %d\n"
+ "hbp = %d\n"
+ "vfp = %d\n"
+ "vsw = %d\n"
+ "vbp = %d\n",
+ edid_timings.hfp,
+ edid_timings.hsw,
+ edid_timings.hbp,
+ edid_timings.vfp,
+ edid_timings.vsw,
+ edid_timings.vbp);
+
+}
+
+/*------------------------------------------------------------------------------
+ | Function : get_edid_timing_data
+ +------------------------------------------------------------------------------
+ | Description : This function gets the resolution information from EDID
+ |
+ | Parameters : void
+ |
+ | Returns : void
+ +----------------------------------------------------------------------------*/
+static int get_edid_timing_data(u8 *edid, u16 *pixel_clk, u16 *horizontal_res,
+ u16 *vertical_res)
+{
+ u8 offset, effective_addrs;
+ u8 count;
+ u8 flag = false;
+ /* Seach block 0, there are 4 DTDs arranged in priority order */
+ for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+ current_descriptor_addrs =
+ EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ *horizontal_res =
+ (((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 4 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+ edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 2 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+ *vertical_res =
+ (((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 7 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+ edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 5 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+ DSSDBG("***Block-0-Timing-descriptor[%d]***\n", count);
+#ifdef EDID_DEBUG
+ for (i = current_descriptor_addrs;
+ i <
+ (current_descriptor_addrs+EDID_TIMING_DESCRIPTOR_SIZE);
+ i++)
+ DSSDBG("%d ==> %x\n", i, edid[i]);
+
+ DSSDBG("E-EDID Buffer Index = 0x%x\n"
+ "horizontal_res = %d\n"
+ "vertical_res = %d\n",
+ current_descriptor_addrs,
+ *horizontal_res,
+ *vertical_res
+ );
+#endif
+ if (*horizontal_res == edid_timings.x_res &&
+ *vertical_res == edid_timings.y_res) {
+ DSSDBG("Found EDID Data for %d x %dp\n",
+ *horizontal_res, *vertical_res);
+ flag = true;
+ break;
+ }
+ }
+
+ /*check for the 1080p in extended block CEA DTDs*/
+ if (flag != true) {
+ offset = edid[EDID_DESCRIPTOR_BLOCK1_ADDRESS + 2];
+ if (offset != 0) {
+ effective_addrs = EDID_DESCRIPTOR_BLOCK1_ADDRESS
+ + offset;
+ /*to determine the number of descriptor blocks */
+ for (count = 0;
+ count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+ count++) {
+ current_descriptor_addrs = effective_addrs +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ *horizontal_res =
+ (((edid[effective_addrs + 4 +
+ count*EDID_TIMING_DESCRIPTOR_SIZE] &
+ 0xF0) << 4) |
+ edid[effective_addrs + 2 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+ *vertical_res =
+ (((edid[effective_addrs + 7 +
+ count*EDID_TIMING_DESCRIPTOR_SIZE] &
+ 0xF0) << 4) |
+ edid[effective_addrs + 5 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+
+ DSSDBG("Block1-Timing-descriptor[%d]\n", count);
+#ifdef EDID_DEBUG
+ for (i = current_descriptor_addrs;
+ i < (current_descriptor_addrs+
+ EDID_TIMING_DESCRIPTOR_SIZE); i++)
+ DSSDBG("%x ==> %x\n",
+ i, edid[i]);
+
+ DSSDBG("current_descriptor = 0x%x\n"
+ "horizontal_res = %d\n"
+ "vertical_res = %d\n",
+ current_descriptor_addrs,
+ *horizontal_res, *vertical_res);
+#endif
+ if (*horizontal_res == edid_timings.x_res &&
+ *vertical_res == edid_timings.y_res) {
+ DSSDBG("Found EDID Data for "
+ "%d x %dp\n",
+ *horizontal_res,
+ *vertical_res
+ );
+ flag = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (flag == true) {
+ *pixel_clk = ((edid[current_descriptor_addrs + 1] << 8) |
+ edid[current_descriptor_addrs]);
+
+ edid_timings.x_res = *horizontal_res;
+ edid_timings.y_res = *vertical_res;
+ edid_timings.pixel_clock = *pixel_clk*10;
+ printk(KERN_INFO "EDID TIMING DATA FOUND\n");
+ DSSDBG("EDID DTD block address = 0x%x\n"
+ "pixel_clk = %d\n"
+ "horizontal res = %d\n"
+ "vertical res = %d\n",
+ current_descriptor_addrs,
+ edid_timings.pixel_clock,
+ edid_timings.x_res,
+ edid_timings.y_res
+ );
+
+ get_horz_vert_timing_info(edid);
+ } else {
+
+ printk(KERN_INFO "EDID TIMING DATA supported NOT FOUND\n");
+ DSSDBG("setting default timing values\n"
+ "pixel_clk = %d\n"
+ "horizontal res = %d\n"
+ "vertical res = %d\n",
+ edid_timings.pixel_clock,
+ edid_timings.x_res,
+ edid_timings.y_res
+ );
+
+ *pixel_clk = edid_timings.pixel_clock;
+ *horizontal_res = edid_timings.x_res;
+ *vertical_res = edid_timings.y_res;
+ }
+
+ return flag;
+}
+
+void hdmi_dump_regs(struct seq_file *s)
+{
+ DSSDBG("0x4a100060 x%x\n", omap_readl(0x4A100060));
+ DSSDBG("0x4A100088 x%x\n", omap_readl(0x4A100088));
+ DSSDBG("0x48055134 x%x\n", omap_readl(0x48055134));
+ DSSDBG("0x48055194 x%x\n", omap_readl(0x48055194));
+}
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
new file mode 100644
index 000000000000..ea2228c6cdb9
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.h
@@ -0,0 +1,245 @@
+/*
+ * drivers/media/video/omap2/dss/hdmi.h
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * hdmi driver
+ */
+#ifndef _OMAP4_HDMI_H_
+#define _OMAP4_HDMI_H_
+
+#define HDMI_EDID_DETAILED_TIMING_OFFSET 0x36 /*EDID Detailed Timing
+ Info 0 begin offset*/
+#define HDMI_EDID_PIX_CLK_OFFSET 0
+#define HDMI_EDID_H_ACTIVE_OFFSET 2
+#define HDMI_EDID_H_BLANKING_OFFSET 3
+#define HDMI_EDID_V_ACTIVE_OFFSET 5
+#define HDMI_EDID_V_BLANKING_OFFSET 6
+#define HDMI_EDID_H_SYNC_OFFSET 8
+#define HDMI_EDID_H_SYNC_PW_OFFSET 9
+#define HDMI_EDID_V_SYNC_OFFSET 10
+#define HDMI_EDID_V_SYNC_PW_OFFSET 10
+#define HDMI_EDID_H_IMAGE_SIZE_OFFSET 12
+#define HDMI_EDID_V_IMAGE_SIZE_OFFSET 13
+#define HDMI_EDID_H_BORDER_OFFSET 15
+#define HDMI_EDID_V_BORDER_OFFSET 16
+#define HDMI_EDID_FLAGS_OFFSET 17
+
+
+#define EDID_TIMING_DESCRIPTOR_SIZE 0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
+
+/* HDMI Connected States */
+#define HDMI_STATE_NOMONITOR 0 /* No HDMI monitor connected*/
+#define HDMI_STATE_CONNECTED 1 /* HDMI monitor connected but powered off*/
+#define HDMI_STATE_ON 2 /* HDMI monitor connected and powered on*/
+
+
+/* HDMI EDID Length */
+#define HDMI_EDID_MAX_LENGTH 256
+
+/* HDMI EDID DTDs */
+#define HDMI_EDID_MAX_DTDS 4
+
+/* HDMI EDID DTD Tags */
+#define HDMI_EDID_DTD_TAG_MONITOR_NAME 0xFC
+#define HDMI_EDID_DTD_TAG_MONITOR_SERIALNUM 0xFF
+#define HDMI_EDID_DTD_TAG_MONITOR_LIMITS 0xFD
+
+
+/* HDMI EDID Extension Data Block Tags */
+#define HDMI_EDID_EX_DATABLOCK_TAG_MASK 0xE0
+#define HDMI_EDID_EX_DATABLOCK_LEN_MASK 0x1F
+
+#define HDMI_EDID_EX_DATABLOCK_AUDIO 0x20
+#define HDMI_EDID_EX_DATABLOCK_VIDEO 0x40
+#define HDMI_EDID_EX_DATABLOCK_VENDOR 0x60
+#define HDMI_EDID_EX_DATABLOCK_SPEAKERS 0x80
+
+/* HDMI EDID Extenion Data Block Values: Video */
+#define HDMI_EDID_EX_VIDEO_NATIVE 0x80
+#define HDMI_EDID_EX_VIDEO_MASK 0x7F
+#define HDMI_EDID_EX_VIDEO_MAX 35
+
+#define HDMI_EDID_EX_VIDEO_640x480p_60Hz_4_3 1
+#define HDMI_EDID_EX_VIDEO_720x480p_60Hz_4_3 2
+#define HDMI_EDID_EX_VIDEO_720x480p_60Hz_16_9 3
+#define HDMI_EDID_EX_VIDEO_1280x720p_60Hz_16_9 4
+#define HDMI_EDID_EX_VIDEO_1920x1080i_60Hz_16_9 5
+#define HDMI_EDID_EX_VIDEO_720x480i_60Hz_4_3 6
+#define HDMI_EDID_EX_VIDEO_720x480i_60Hz_16_9 7
+#define HDMI_EDID_EX_VIDEO_720x240p_60Hz_4_3 8
+#define HDMI_EDID_EX_VIDEO_720x240p_60Hz_16_9 9
+#define HDMI_EDID_EX_VIDEO_2880x480i_60Hz_4_3 10
+#define HDMI_EDID_EX_VIDEO_2880x480i_60Hz_16_9 11
+#define HDMI_EDID_EX_VIDEO_2880x480p_60Hz_4_3 12
+#define HDMI_EDID_EX_VIDEO_2880x480p_60Hz_16_9 13
+#define HDMI_EDID_EX_VIDEO_1440x480p_60Hz_4_3 14
+#define HDMI_EDID_EX_VIDEO_1440x480p_60Hz_16_9 15
+#define HDMI_EDID_EX_VIDEO_1920x1080p_60Hz_16_9 16
+#define HDMI_EDID_EX_VIDEO_720x576p_50Hz_4_3 17
+#define HDMI_EDID_EX_VIDEO_720x576p_50Hz_16_9 18
+#define HDMI_EDID_EX_VIDEO_1280x720p_50Hz_16_9 19
+#define HDMI_EDID_EX_VIDEO_1920x1080i_50Hz_16_9 20
+#define HDMI_EDID_EX_VIDEO_720x576i_50Hz_4_3 21
+#define HDMI_EDID_EX_VIDEO_720x576i_50Hz_16_9 22
+#define HDMI_EDID_EX_VIDEO_720x288p_50Hz_4_3 23
+#define HDMI_EDID_EX_VIDEO_720x288p_50Hz_16_9 24
+#define HDMI_EDID_EX_VIDEO_2880x576i_50Hz_4_3 25
+#define HDMI_EDID_EX_VIDEO_2880x576i_50Hz_16_9 26
+#define HDMI_EDID_EX_VIDEO_2880x288p_50Hz_4_3 27
+#define HDMI_EDID_EX_VIDEO_2880x288p_50Hz_16_9 28
+#define HDMI_EDID_EX_VIDEO_1440x576p_50Hz_4_3 29
+#define HDMI_EDID_EX_VIDEO_1440x576p_50Hz_16_9 30
+#define HDMI_EDID_EX_VIDEO_1920x1080p_50Hz_16_9 31
+#define HDMI_EDID_EX_VIDEO_1920x1080p_24Hz_16_9 32
+#define HDMI_EDID_EX_VIDEO_1920x1080p_25Hz_16_9 33
+#define HDMI_EDID_EX_VIDEO_1920x1080p_30Hz_16_9 34
+
+/*--------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Video Descriptor Block */
+typedef struct {
+ u8 pixel_clock[2]; /* 54-55 */
+ u8 horiz_active; /* 56 */
+ u8 horiz_blanking; /* 57 */
+ u8 horiz_high; /* 58 */
+ u8 vert_active; /* 59 */
+ u8 vert_blanking; /* 60 */
+ u8 vert_high; /* 61 */
+ u8 horiz_sync_offset; /* 62 */
+ u8 horiz_sync_pulse; /* 63 */
+ u8 vert_sync_pulse; /* 64 */
+ u8 sync_pulse_high; /* 65 */
+ u8 horiz_image_size; /* 66 */
+ u8 vert_image_size; /* 67 */
+ u8 image_size_high; /* 68 */
+ u8 horiz_border; /* 69 */
+ u8 vert_border; /* 70 */
+ u8 misc_settings; /* 71 */
+}
+HDMI_EDID_DTD_VIDEO;
+
+
+/* Monitor Limits Descriptor Block */
+typedef struct {
+ u8 pixel_clock[2]; /* 54-55*/
+ u8 _reserved1; /* 56 */
+ u8 block_type; /* 57 */
+ u8 _reserved2; /* 58 */
+ u8 min_vert_freq; /* 59 */
+ u8 max_vert_freq; /* 60 */
+ u8 min_horiz_freq; /* 61 */
+ u8 max_horiz_freq; /* 62 */
+ u8 pixel_clock_mhz; /* 63 */
+
+ u8 GTF[2]; /* 64 -65 */
+ u8 start_horiz_freq; /* 66 */
+ u8 C; /* 67 */
+ u8 M[2]; /* 68-69 */
+ u8 K; /* 70 */
+ u8 J; /* 71 */
+}
+HDMI_EDID_DTD_MONITOR;
+
+
+/* Text Descriptor Block */
+typedef struct {
+ u8 pixel_clock[2]; /* 54-55 */
+ u8 _reserved1; /* 56 */
+ u8 block_type; /* 57 */
+ u8 _reserved2; /* 58 */
+
+ u8 text[13]; /* 59-71 */
+}
+HDMI_EDID_DTD_TEXT;
+
+
+/* DTD Union */
+typedef union {
+ HDMI_EDID_DTD_VIDEO video;
+ HDMI_EDID_DTD_TEXT monitor_name;
+ HDMI_EDID_DTD_TEXT monitor_serial_number;
+ HDMI_EDID_DTD_MONITOR monitor_limits;
+}
+HDMI_EDID_DTD;
+
+
+/* EDID struct */
+typedef struct {
+ u8 header[8]; /* 00-07 */
+ u8 manufacturerID[2]; /* 08-09 */
+ u8 product_id[2]; /* 10-11 */
+ u8 serial_number[4]; /* 12-15 */
+ u8 week_manufactured; /* 16 */
+ u8 year_manufactured; /* 17 */
+ u8 edid_version; /* 18 */
+ u8 edid_revision; /* 19 */
+
+ u8 video_in_definition; /* 20 */
+ u8 max_horiz_image_size; /* 21 */
+ u8 max_vert_image_size; /* 22 */
+ u8 display_gamma; /* 23 */
+ u8 power_features; /* 24 */
+ u8 chroma_info[10]; /* 25-34 */
+ u8 timing_1; /* 35 */
+ u8 timing_2; /* 36 */
+ u8 timing_3; /* 37 */
+ u8 std_timings[16]; /* 38-53 */
+
+ HDMI_EDID_DTD DTD[4]; /* 72-125 */
+
+ u8 extension_edid; /* 126 */
+ u8 checksum; /* 127 */
+
+ u8 extension_tag; /* 00 (extensions follow EDID) */
+ u8 extention_rev; /* 01 */
+ u8 offset_dtd; /* 02 */
+ u8 num_dtd; /* 03 */
+
+ u8 data_block[123]; /* 04 - 126 */
+ u8 extension_checksum; /* 127 */
+ }
+HDMI_EDID;
+
+static int hdmi_enable_display(struct omap_dss_device *dssdev);
+static void hdmi_disable_display(struct omap_dss_device *dssdev);
+static int hdmi_display_suspend(struct omap_dss_device *dssdev);
+static int hdmi_display_resume(struct omap_dss_device *dssdev);
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+static void hdmi_set_custom_edid_timing_code(struct omap_dss_device *dssdev, int code , int mode);
+static void hdmi_get_edid(struct omap_dss_device *dssdev);
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+static int hdmi_read_edid(struct omap_video_timings *);
+static int get_edid_timing_data(u8 *edid, u16 *pixel_clk, u16 *horizontal_res,
+ u16 *vertical_res);
+void show_horz_vert_timing_info(u8 *edid);
+int hdmi_get_image_format(void);
+int hdmi_get_audio_format(void);
+static irqreturn_t hdmi_irq_handler(int irq, void *arg);
+static int hdmi_enable_hpd(struct omap_dss_device *dssdev);
+static void hdmi_power_off(struct omap_dss_device *dssdev);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
+
+
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 0820986d4a68..2f32160c8375 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -34,6 +34,8 @@
#include "dss.h"
+#define MAX_DSS_MANAGERS (cpu_is_omap44xx() ? 3 : 2)
+
static int num_managers;
static struct list_head manager_list;
@@ -415,6 +417,8 @@ struct overlay_cache_data {
u32 fifo_high;
bool manual_update;
+ enum omap_overlay_zorder zorder;
+ u32 p_uv_addr; /* relevent for NV12 format only */
};
struct manager_cache_data {
@@ -444,8 +448,9 @@ struct manager_cache_data {
static struct {
spinlock_t lock;
- struct overlay_cache_data overlay_cache[3];
- struct manager_cache_data manager_cache[2];
+ struct overlay_cache_data overlay_cache[4];
+ struct manager_cache_data manager_cache[3];
+ struct writeback_cache_data writeback_cache;
bool irq_enabled;
} dss_cache;
@@ -509,9 +514,20 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
- else
- irq = DISPC_IRQ_VSYNC;
-
+ else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
+ irq = DISPC_IRQ_EVSYNC_EVEN;
+ else if ((mgr->device->type == OMAP_DISPLAY_TYPE_DSI)
+ && (mgr->device->channel == OMAP_DSS_CHANNEL_LCD))
+ irq = DISPC_IRQ_FRAMEDONE;
+ else if ((mgr->device->type == OMAP_DISPLAY_TYPE_DSI)
+ && (mgr->device->channel == OMAP_DSS_CHANNEL_LCD2))
+ irq = DISPC_IRQ_FRAMEDONE2;
+ else if ((mgr->device->type == OMAP_DISPLAY_TYPE_DPI)
+ && (mgr->device->channel == OMAP_DSS_CHANNEL_LCD))
+ irq = DISPC_IRQ_VSYNC;
+ else if ((mgr->device->type == OMAP_DISPLAY_TYPE_DPI)
+ && (mgr->device->channel == OMAP_DSS_CHANNEL_LCD2))
+ irq = DISPC_IRQ_VSYNC2;
return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
}
@@ -527,10 +543,10 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (!dssdev)
return 0;
-
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ channel = mgr->device->channel;
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
- channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
@@ -538,11 +554,16 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
- irq = DISPC_IRQ_FRAMEDONE;
+ irq = (channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE
+ : DISPC_IRQ_FRAMEDONE2;
+
} else {
- irq = DISPC_IRQ_VSYNC;
+ irq = (channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_VSYNC
+ : DISPC_IRQ_VSYNC2;
+
}
- channel = OMAP_DSS_CHANNEL_LCD;
}
mc = &dss_cache.manager_cache[mgr->id];
@@ -600,10 +621,11 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
return 0;
dssdev = ovl->manager->device;
+ channel = dssdev->channel;
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
- channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
@@ -611,11 +633,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
- irq = DISPC_IRQ_FRAMEDONE;
+ irq = (channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE
+ : DISPC_IRQ_FRAMEDONE2;
} else {
- irq = DISPC_IRQ_VSYNC;
+ irq = (channel == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_VSYNC
+ : DISPC_IRQ_VSYNC2;
}
- channel = OMAP_DSS_CHANNEL_LCD;
}
oc = &dss_cache.overlay_cache[ovl->id];
@@ -816,7 +841,9 @@ static int configure_overlay(enum omap_plane plane)
c->rotation_type,
c->rotation,
c->mirror,
- c->global_alpha);
+ c->global_alpha,
+ c->channel,
+ c->p_uv_addr);
if (r) {
/* this shouldn't happen */
@@ -828,8 +855,22 @@ static int configure_overlay(enum omap_plane plane)
dispc_enable_replication(plane, c->replication);
dispc_set_burst_size(plane, c->burst_size);
+ dispc_set_zorder(plane, c->zorder);
+ dispc_enable_zorder(plane, 1);
dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
-
+ if (cpu_is_omap44xx()) {
+ struct writeback_cache_data *wb;
+ wb = &dss_cache.writeback_cache;
+ /*if writeback is enabled and input source is the current overlay
+ set writeback values and enable wb plane before source plane*/
+ if ((wb->enabled) &&
+ (omap_dss_check_wb(wb, plane, c->channel))) {
+ /* writeback is enabled for this plane - set accordingly */
+ dispc_setup_wb(wb);
+ wb->dirty = false;
+ wb->shadow_dirty = true;
+ }
+ }
dispc_enable_plane(plane, 1);
return 0;
@@ -856,21 +897,25 @@ static int configure_dispc(void)
{
struct overlay_cache_data *oc;
struct manager_cache_data *mc;
+ struct writeback_cache_data *wb;
const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
- const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+ const int num_mgrs = MAX_DSS_MANAGERS;
int i;
int r;
- bool mgr_busy[2];
- bool mgr_go[2];
+ bool mgr_busy[MAX_DSS_MANAGERS];
+ bool mgr_go[MAX_DSS_MANAGERS];
bool busy;
r = 0;
busy = false;
- mgr_busy[0] = dispc_go_busy(0);
- mgr_busy[1] = dispc_go_busy(1);
- mgr_go[0] = false;
- mgr_go[1] = false;
+ for (i = 0; i < num_mgrs; i++) {
+ mgr_busy[i] = dispc_go_busy(i);
+ mgr_go[i] = false;
+ }
+
+ if (cpu_is_omap44xx())
+ wb = &dss_cache.writeback_cache;
/* Commit overlay settings */
for (i = 0; i < num_ovls; ++i) {
@@ -894,7 +939,12 @@ static int configure_dispc(void)
oc->dirty = false;
oc->shadow_dirty = true;
+ if (!cpu_is_omap44xx())
mgr_go[oc->channel] = true;
+ else
+ if (!omap_dss_check_wb(wb, i, -1))
+ /*skip manager go if WB enabled*/
+ mgr_go[oc->channel] = true;
}
/* Commit manager settings */
@@ -917,7 +967,28 @@ static int configure_dispc(void)
mc->shadow_dirty = true;
mgr_go[i] = true;
}
-
+ if (cpu_is_omap44xx()) {
+ /*Enable WB plane and source plane */
+ DSSDBG("configure manager wb->shadow_dirty = %d", wb->shadow_dirty);
+ if (wb->shadow_dirty && wb->enabled) {
+ DSSDBG("dispc_go_wb_is called after enabling input plane and then WB");
+ switch (wb->source) {
+ case OMAP_WB_OVERLAY0:
+ case OMAP_WB_OVERLAY1:
+ case OMAP_WB_OVERLAY2:
+ case OMAP_WB_OVERLAY3:
+ dispc_enable_plane(wb->source - 3, 1);
+ break;
+ case OMAP_WB_LCD_1_MANAGER:
+ case OMAP_WB_LCD_2_MANAGER:
+ case OMAP_WB_TV_MANAGER:
+ ;/*Do nothing As of now as we dont support Manager yet with WB*/
+ }
+ dispc_go_wb();
+ wb->shadow_dirty = false;
+ dispc_enable_plane(OMAP_DSS_WB, 1);
+ }
+ }
/* set GO */
for (i = 0; i < num_mgrs; ++i) {
mc = &dss_cache.manager_cache[i];
@@ -940,6 +1011,22 @@ static int configure_dispc(void)
return r;
}
+/* Make the coordinates even. There are some strange problems with OMAP and
+ * partial DSI update when the update widths are odd. */
+static void make_even(u16 *x, u16 *w)
+{
+ u16 x1, x2;
+
+ x1 = *x;
+ x2 = *x + *w;
+
+ x1 &= ~1;
+ x2 = ALIGN(x2, 2);
+
+ *x = x1;
+ *w = x2 - x1;
+}
+
/* Configure dispc for partial update. Return possibly modified update
* area */
void dss_setup_partial_planes(struct omap_dss_device *dssdev,
@@ -968,6 +1055,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
return;
}
+ make_even(&x, &w);
+
spin_lock_irqsave(&dss_cache.lock, flags);
/* We need to show the whole overlay if it is scaled. So look for
@@ -1029,6 +1118,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
w = x2 - x1;
h = y2 - y1;
+ make_even(&x, &w);
+
DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
i, x, y, w, h);
}
@@ -1057,7 +1148,7 @@ void dss_start_update(struct omap_dss_device *dssdev)
struct manager_cache_data *mc;
struct overlay_cache_data *oc;
const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
- const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+ const int num_mgrs = MAX_DSS_MANAGERS;
struct omap_overlay_manager *mgr;
int i;
@@ -1089,10 +1180,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
int i, r;
- bool mgr_busy[2];
+ bool mgr_busy[MAX_DSS_MANAGERS];
- mgr_busy[0] = dispc_go_busy(0);
- mgr_busy[1] = dispc_go_busy(1);
+ for (i = 0; i < num_mgrs; i++)
+ mgr_busy[i] = dispc_go_busy(i);
spin_lock(&dss_cache.lock);
@@ -1125,7 +1216,7 @@ static void dss_apply_irq_handler(void *data, u32 mask)
omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
- DISPC_IRQ_EVSYNC_EVEN);
+ DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_VSYNC2);
dss_cache.irq_enabled = false;
end:
@@ -1186,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->dirty = true;
oc->paddr = ovl->info.paddr;
+ oc->p_uv_addr = ovl->info.p_uv_addr;
oc->vaddr = ovl->info.vaddr;
oc->screen_width = ovl->info.screen_width;
oc->width = ovl->info.width;
@@ -1199,6 +1291,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->out_width = ovl->info.out_width;
oc->out_height = ovl->info.out_height;
oc->global_alpha = ovl->info.global_alpha;
+ oc->zorder = ovl->info.zorder;
oc->replication =
dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1298,6 +1391,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
case OMAP_DISPLAY_TYPE_DBI:
case OMAP_DISPLAY_TYPE_SDI:
case OMAP_DISPLAY_TYPE_VENC:
+ case OMAP_DISPLAY_TYPE_HDMI:
default_get_overlay_fifo_thresholds(ovl->id, size,
&oc->burst_size, &oc->fifo_low,
&oc->fifo_high);
@@ -1319,7 +1413,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
if (!dss_cache.irq_enabled) {
r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
- DISPC_IRQ_EVSYNC_EVEN);
+ DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_VSYNC2);
dss_cache.irq_enabled = true;
}
configure_dispc();
@@ -1330,6 +1424,274 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
return r;
}
+int count_wb_manager = 0;
+void wb_irq_handler(void *data, u32 mask)
+{
+ count_wb_manager++;
+ DSSDBG("Framedone wb count = %d", count_wb_manager);
+}
+
+int omap_dss_wb_apply(struct omap_overlay_manager *mgr, struct omap_writeback *wb)
+{
+ struct overlay_cache_data *oc;
+ struct manager_cache_data *mc;
+ int i, j;
+ struct omap_overlay *ovl;
+ int num_planes_enabled = 0;
+ bool use_fifomerge;
+ unsigned long flags;
+ int r;
+ struct writeback_cache_data *wbc;
+
+ DSSDBG("omap_dss_wb_apply(%s)\n", mgr->name);
+
+ spin_lock_irqsave(&dss_cache.lock, flags);
+
+ /* Configure overlays */
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_dss_device *dssdev;
+
+ ovl = omap_dss_get_overlay(i);
+
+ if (ovl == NULL)
+ break;
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ oc = &dss_cache.overlay_cache[ovl->id];
+
+ if (!overlay_enabled(ovl)) {
+ if (oc->enabled) {
+ oc->enabled = false;
+ oc->dirty = true;
+ }
+ continue;
+ }
+ oc->enabled = true;
+
+ if (!ovl->info_dirty) {
+ if (oc->enabled)
+ ++num_planes_enabled;
+ continue;
+ }
+
+ dssdev = ovl->manager->device;
+
+ if (dss_check_overlay(ovl, dssdev)) {
+ if (oc->enabled) {
+ oc->enabled = false;
+ oc->dirty = true;
+ }
+ continue;
+ }
+
+ ovl->info_dirty = false;
+ oc->dirty = true;
+
+ oc->paddr = ovl->info.paddr;
+ oc->p_uv_addr = ovl->info.p_uv_addr;
+ oc->zorder = ovl->info.zorder;
+ oc->vaddr = ovl->info.vaddr;
+ oc->screen_width = ovl->info.screen_width;
+ oc->width = ovl->info.width;
+ oc->height = ovl->info.height;
+ oc->color_mode = ovl->info.color_mode;
+ oc->rotation = ovl->info.rotation;
+ oc->rotation_type = ovl->info.rotation_type;
+ oc->mirror = ovl->info.mirror;
+ oc->pos_x = ovl->info.pos_x;
+ oc->pos_y = ovl->info.pos_y;
+ oc->out_width = ovl->info.out_width;
+ oc->out_height = ovl->info.out_height;
+ oc->global_alpha = ovl->info.global_alpha;
+
+ oc->replication =
+ dss_use_replication(dssdev, ovl->info.color_mode);
+
+ oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
+
+ oc->channel = ovl->manager->id;
+ /* TODO: to change with dssdev->channel? */
+
+ oc->enabled = true;
+
+ oc->manual_update =
+ dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
+ dssdev->driver->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+
+ ++num_planes_enabled;
+ wbc = &dss_cache.writeback_cache;
+
+ if (!wb->first_time) {
+ DSSDBG("entered wb_first time\n");
+ wbc->enabled = true;
+ wbc->source = wb->info.source;
+ wbc->source_type = wb->info.source_type;
+ wb->first_time = true;
+ }
+ DSSDBG("dss_wb_apply %d\n", wbc->enabled);
+ /* Configure Write-back - check for connect with this overlay*/
+ if ((wbc->enabled) &&
+ (omap_dss_check_wb(wbc, ovl->id , ovl->manager->id))) {
+
+ DSSDBG("dss_mgr_apply paddr = %lx", wb->info.paddr);
+ for (j = 0 ; j < 1 ; j++) {
+ if (!wb->enabled) {
+ if (wbc->enabled) {
+ wbc->enabled = false;
+ wbc->dirty = true;
+ }
+ continue;
+ }
+ if (!wb->info_dirty)
+ continue;
+
+ wb->info_dirty = false;
+ wbc->dirty = true;
+
+ wbc->color_mode = wb->info.dss_mode;
+ wbc->input_color_mode = oc->color_mode;
+ /*OMAP_DSS_COLOR_ARGB32; */
+ wbc->width = wb->info.width;
+ wbc->height = wb->info.height;
+ wbc->input_width = ovl->info.width;
+ wbc->input_height = ovl->info.height;
+
+ wbc->paddr = wb->info.paddr;
+ wbc->puv_addr = wb->info.puv_addr;
+
+ wbc->enabled = true;
+
+ wbc->capturemode = wb->info.capturemode;
+ wbc->burst_size = OMAP_DSS_BURST_16x32; /* 8x128 - min. for OMAP4 */
+ wbc->source = wb->info.source;
+
+ /* TODO: Set fifo high, fifo low values ? */
+ wbc->fifo_high = 0x28A;
+ wbc->fifo_low = 0XFA;
+ }
+ }
+ }
+ if (count_wb_manager == 0)
+ omap_dispc_register_isr(wb_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE_WB);
+ /* Configure managers */
+ list_for_each_entry(mgr, &manager_list, list) {
+ struct omap_dss_device *dssdev;
+
+ if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
+ continue;
+
+ mc = &dss_cache.manager_cache[mgr->id];
+
+ if (mgr->device_changed) {
+ mgr->device_changed = false;
+ mgr->info_dirty = true;
+ }
+
+ if (!mgr->info_dirty)
+ continue;
+
+ if (!mgr->device)
+ continue;
+
+ dssdev = mgr->device;
+
+ mgr->info_dirty = false;
+ mc->dirty = true;
+
+ mc->default_color = mgr->info.default_color;
+ mc->trans_key_type = mgr->info.trans_key_type;
+ mc->trans_key = mgr->info.trans_key;
+ mc->trans_enabled = mgr->info.trans_enabled;
+ mc->alpha_enabled = mgr->info.alpha_enabled;
+
+ mc->manual_upd_display =
+ dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
+
+ mc->manual_update =
+ dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
+ dssdev->driver->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+ }
+
+ /* XXX TODO: Try to get fifomerge working. The problem is that it
+ * affects both managers, not individually but at the same time. This
+ * means the change has to be well synchronized. I guess the proper way
+ * is to have a two step process for fifo merge:
+ * fifomerge enable:
+ * 1. disable other planes, leaving one plane enabled
+ * 2. wait until the planes are disabled on HW
+ * 3. config merged fifo thresholds, enable fifomerge
+ * fifomerge disable:
+ * 1. config unmerged fifo thresholds, disable fifomerge
+ * 2. wait until fifo changes are in HW
+ * 3. enable planes
+ */
+ use_fifomerge = false;
+
+ /* Configure overlay fifos */
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_dss_device *dssdev;
+ u32 size;
+
+ ovl = omap_dss_get_overlay(i);
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ oc = &dss_cache.overlay_cache[ovl->id];
+
+ if (!oc->enabled)
+ continue;
+
+ dssdev = ovl->manager->device;
+
+ size = dispc_get_plane_fifo_size(ovl->id);
+ if (use_fifomerge)
+ size *= 3;
+
+ switch (dssdev->type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ case OMAP_DISPLAY_TYPE_DBI:
+ case OMAP_DISPLAY_TYPE_SDI:
+ case OMAP_DISPLAY_TYPE_VENC:
+ case OMAP_DISPLAY_TYPE_HDMI:
+ default_get_overlay_fifo_thresholds(ovl->id, size,
+ &oc->burst_size, &oc->fifo_low,
+ &oc->fifo_high);
+ break;
+#ifdef CONFIG_OMAP2_DSS_DSI
+ case OMAP_DISPLAY_TYPE_DSI:
+ dsi_get_overlay_fifo_thresholds(ovl->id, size,
+ &oc->burst_size, &oc->fifo_low,
+ &oc->fifo_high);
+ break;
+#endif
+ default:
+ BUG();
+ }
+ }
+
+ r = 0;
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ if (!dss_cache.irq_enabled) {
+ r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
+ DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
+ DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_VSYNC2);
+
+ dss_cache.irq_enabled = true;
+ }
+ configure_dispc();
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+
+ spin_unlock_irqrestore(&dss_cache.lock, flags);
+
+ return r;
+}
+
+EXPORT_SYMBOL(omap_dss_wb_apply);
+
static int dss_check_manager(struct omap_overlay_manager *mgr)
{
/* OMAP supports only graphics source transparency color key and alpha
@@ -1396,7 +1758,7 @@ int dss_init_overlay_managers(struct platform_device *pdev)
num_managers = 0;
- for (i = 0; i < 2; ++i) {
+ for (i = 0; i < MAX_DSS_MANAGERS; ++i) {
struct omap_overlay_manager *mgr;
mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
@@ -1413,8 +1775,17 @@ int dss_init_overlay_managers(struct platform_device *pdev)
case 1:
mgr->name = "tv";
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
- mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
+ mgr->supported_displays =
+ OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI;
break;
+ case 2:
+ mgr->name = "2lcd";
+ mgr->id = OMAP_DSS_CHANNEL_LCD2;
+ mgr->supported_displays =
+ OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_SDI |
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DSI;
+ break;
+
}
mgr->set_device = &omap_dss_set_device;
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 82336583adef..2462f51a6900 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -36,6 +36,8 @@
#include "dss.h"
+#define MAX_DSS_OVERLAYS (cpu_is_omap44xx() ? 4 : 3)
+
static int num_overlays;
static struct list_head overlay_list;
@@ -56,6 +58,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
int i, r;
struct omap_overlay_manager *mgr = NULL;
struct omap_overlay_manager *old_mgr;
+ struct omap_overlay_info info;
int len = size;
if (buf[size-1] == '\n')
@@ -81,6 +84,16 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
if (mgr == ovl->manager)
return size;
+ if (sysfs_streq(mgr->name, "tv")) {
+ ovl->get_overlay_info(ovl, &info);
+ if (mgr->device->panel.timings.x_res < info.width ||
+ mgr->device->panel.timings.y_res < info.height) {
+ printk(KERN_ERR"TV does not support downscaling"
+ "Please configure overlay to supported format");
+ return -EINVAL;
+ }
+ }
+
old_mgr = ovl->manager;
/* detach old manager */
@@ -166,18 +179,28 @@ static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
- int r;
+ int r, out_width, out_height;
char *last;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
- info.out_width = simple_strtoul(buf, &last, 10);
+ out_width = simple_strtoul(buf, &last, 10);
++last;
if (last - buf >= size)
return -EINVAL;
- info.out_height = simple_strtoul(last, &last, 10);
+ out_height = simple_strtoul(last, &last, 10);
+
+ if (sysfs_streq(ovl->manager->name, "tv")) {
+ if (ovl->manager->device->panel.timings.x_res < out_width ||
+ ovl->manager->device->panel.timings.y_res < out_height)
+ printk(KERN_ERR"TV does not support downscaling , Wrong output size");
+ return -EINVAL;
+ }
+
+ info.out_width = out_width;
+ info.out_height = out_height;
r = ovl->set_overlay_info(ovl, &info);
if (r)
@@ -234,10 +257,10 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
ovl->get_overlay_info(ovl, &info);
- /* Video1 plane does not support global alpha
+ /* In OMAP2/3 Video1 plane does not support global alpha
* to always make it 255 completely opaque
*/
- if (ovl->id == OMAP_DSS_VIDEO1)
+ if ((!cpu_is_omap44xx()) && (ovl->id == OMAP_DSS_VIDEO1))
info.global_alpha = 255;
else
info.global_alpha = simple_strtoul(buf, NULL, 10);
@@ -255,6 +278,35 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
return size;
}
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ovl->info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.zorder = simple_strtoul(buf, NULL, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
@@ -278,6 +330,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
overlay_enabled_show, overlay_enabled_store);
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+ overlay_zorder_show, overlay_zorder_store);
+
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
@@ -288,6 +343,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_output_size.attr,
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
+ &overlay_attr_zorder.attr,
NULL
};
@@ -392,6 +448,12 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
return -EINVAL;
}
+ if ((info->zorder < OMAP_DSS_OVL_ZORDER_0) ||
+ (info->zorder > OMAP_DSS_OVL_ZORDER_3)) {
+ DSSERR("overlay doesn't support zorder %d\n", info->zorder);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -510,11 +572,11 @@ static void omap_dss_add_overlay(struct omap_overlay *overlay)
list_add_tail(&overlay->list, &overlay_list);
}
-static struct omap_overlay *dispc_overlays[3];
+static struct omap_overlay *dispc_overlays[4];
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
{
- mgr->num_overlays = 3;
+ mgr->num_overlays = MAX_DSS_OVERLAYS;
mgr->overlays = dispc_overlays;
}
@@ -535,7 +597,7 @@ void dss_init_overlays(struct platform_device *pdev)
num_overlays = 0;
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < MAX_DSS_OVERLAYS; ++i) {
struct omap_overlay *ovl;
ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
@@ -545,32 +607,48 @@ void dss_init_overlays(struct platform_device *pdev)
case 0:
ovl->name = "gfx";
ovl->id = OMAP_DSS_GFX;
- ovl->supported_modes = cpu_is_omap34xx() ?
+ ovl->supported_modes = (cpu_is_omap44xx() |
+ cpu_is_omap34xx()) ?
OMAP_DSS_COLOR_GFX_OMAP3 :
OMAP_DSS_COLOR_GFX_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = OMAP_DSS_OVL_ZORDER_0;
break;
case 1:
ovl->name = "vid1";
ovl->id = OMAP_DSS_VIDEO1;
- ovl->supported_modes = cpu_is_omap34xx() ?
+ ovl->supported_modes = (cpu_is_omap44xx() |
+ cpu_is_omap34xx()) ?
OMAP_DSS_COLOR_VID1_OMAP3 :
OMAP_DSS_COLOR_VID_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = OMAP_DSS_OVL_ZORDER_3;
break;
case 2:
ovl->name = "vid2";
ovl->id = OMAP_DSS_VIDEO2;
- ovl->supported_modes = cpu_is_omap34xx() ?
+ ovl->supported_modes = (cpu_is_omap44xx() |
+ cpu_is_omap34xx()) ?
OMAP_DSS_COLOR_VID2_OMAP3 :
OMAP_DSS_COLOR_VID_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = OMAP_DSS_OVL_ZORDER_2;
break;
+ case 3:
+ ovl->name = "vid3";
+ ovl->id = OMAP_DSS_VIDEO3;
+ ovl->supported_modes = OMAP_DSS_COLOR_VID3_OMAP3;
+ ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
+ OMAP_DSS_OVL_CAP_DISPC;
+ ovl->info.global_alpha = 255;
+ ovl->info.zorder = OMAP_DSS_OVL_ZORDER_1;
+ break;
+
}
ovl->set_manager = &omap_dss_set_manager;
@@ -627,21 +705,35 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
int i;
struct omap_overlay_manager *lcd_mgr;
struct omap_overlay_manager *tv_mgr;
+ struct omap_overlay_manager *lcd2_mgr = NULL;
struct omap_overlay_manager *mgr = NULL;
lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
-
- if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
- if (!lcd_mgr->device || force) {
- if (lcd_mgr->device)
- lcd_mgr->unset_device(lcd_mgr);
- lcd_mgr->set_device(lcd_mgr, dssdev);
- mgr = lcd_mgr;
+ if (cpu_is_omap44xx())
+ lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2);
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
+ if (!lcd2_mgr->device || force || sysfs_streq(dssdev->name, "2lcd")) {
+ if (lcd2_mgr->device)
+ lcd2_mgr->unset_device(lcd2_mgr);
+ lcd2_mgr->set_device(lcd2_mgr, dssdev);
+ mgr = lcd2_mgr;
+ }
+ } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
+ && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
+ if (lcd2_mgr) {
+ if (!lcd_mgr->device || force) {
+ if (lcd_mgr->device)
+ lcd_mgr->unset_device(lcd_mgr);
+ lcd_mgr->set_device(lcd_mgr, dssdev);
+ mgr = lcd_mgr;
+ }
}
}
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
if (!tv_mgr->device || force) {
if (tv_mgr->device)
tv_mgr->unset_device(tv_mgr);
@@ -651,7 +743,7 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
}
if (mgr) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < MAX_DSS_OVERLAYS; i++) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
if (!ovl->manager || force) {
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index cc23f53cc62d..a9fbb45ca52f 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -311,7 +311,7 @@ void rfbi_transfer_area(u16 width, u16 height,
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
- dispc_set_lcd_size(width, height);
+ dispc_set_lcd_size(OMAP_DSS_CHANNEL_LCD, width, height);
dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
@@ -1018,11 +1018,14 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
goto err1;
}
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+ dispc_set_lcd_display_type(OMAP_DSS_CHANNEL_LCD,
+ OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
+ dispc_set_parallel_interface_mode(OMAP_DSS_CHANNEL_LCD,
+ OMAP_DSS_PARALLELMODE_RFBI);
- dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+ dispc_set_tft_data_lines(OMAP_DSS_CHANNEL_LCD,
+ dssdev->ctrl.pixel_size);
rfbi_configure(dssdev->phy.rfbi.channel,
dssdev->ctrl.pixel_size,
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 12eb4042dd82..95e6a53df75f 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -23,21 +23,26 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
+#include <plat/cpu.h>
#include "dss.h"
static struct {
bool skip_init;
bool update_enabled;
+ struct regulator *vdds_sdi_reg;
} sdi;
static void sdi_basic_init(void)
{
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
+ dispc_set_parallel_interface_mode(OMAP_DSS_CHANNEL_LCD,
+ OMAP_DSS_PARALLELMODE_BYPASS);
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_tft_data_lines(24);
+ dispc_set_lcd_display_type(OMAP_DSS_CHANNEL_LCD,
+ OMAP_DSS_LCD_DISPLAY_TFT);
+ dispc_set_tft_data_lines(OMAP_DSS_CHANNEL_LCD, 24);
dispc_lcd_enable_signal_polarity(1);
}
@@ -57,6 +62,10 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
+ r = regulator_enable(sdi.vdds_sdi_reg);
+ if (r)
+ goto err1;
+
/* In case of skip_init sdi_init has already enabled the clocks */
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -66,15 +75,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
/* 15.5.9.1.2 */
dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
- dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
- dssdev->panel.acb);
+ dispc_set_pol_freq(OMAP_DSS_CHANNEL_LCD, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
if (!sdi.skip_init) {
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
&dss_cinfo, &dispc_cinfo);
} else {
r = dss_get_clock_div(&dss_cinfo);
- r = dispc_get_clock_div(&dispc_cinfo);
+ r = dispc_get_clock_div(OMAP_DSS_CHANNEL_LCD, &dispc_cinfo);
}
if (r)
@@ -95,7 +104,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
- dispc_set_lcd_timings(t);
+ dispc_set_lcd_timings(OMAP_DSS_CHANNEL_LCD, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
@@ -115,19 +124,12 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
dssdev->manager->enable(dssdev->manager);
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err3;
- }
-
sdi.skip_init = 0;
return 0;
-err3:
- dssdev->manager->disable(dssdev->manager);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ regulator_disable(sdi.vdds_sdi_reg);
err1:
omap_dss_stop_device(dssdev);
err0:
@@ -137,15 +139,14 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->driver->disable)
- dssdev->driver->disable(dssdev);
-
dssdev->manager->disable(dssdev->manager);
dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ regulator_disable(sdi.vdds_sdi_reg);
+
omap_dss_stop_device(dssdev);
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
@@ -162,6 +163,11 @@ int sdi_init(bool skip_init)
/* we store this for first display enable, then clear it */
sdi.skip_init = skip_init;
+ sdi.vdds_sdi_reg = dss_get_vdds_sdi();
+ if (IS_ERR(sdi.vdds_sdi_reg)) {
+ DSSERR("can't get VDDS_SDI regulator\n");
+ return PTR_ERR(sdi.vdds_sdi_reg);
+ }
/*
* Enable clocks already here, otherwise there would be a toggle
* of them until sdi_display_enable is called.
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index f0ba5732d84a..eff35050e28a 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -479,12 +479,6 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
goto err1;
}
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err2;
- }
-
venc_power_on(dssdev);
venc.wss_data = 0;
@@ -494,13 +488,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- mutex_unlock(&venc.venc_lock);
-
- return r;
-err2:
- venc_power_off(dssdev);
err1:
mutex_unlock(&venc.venc_lock);
+
return r;
}
@@ -524,9 +514,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
/* wait at least 5 vsyncs after disabling the LCD */
msleep(100);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
end:
mutex_unlock(&venc.venc_lock);
diff --git a/drivers/video/omap2/dss/wb.c b/drivers/video/omap2/dss/wb.c
new file mode 100644
index 000000000000..02f9a7a18df1
--- /dev/null
+++ b/drivers/video/omap2/dss/wb.c
@@ -0,0 +1,179 @@
+/*
+ * linux/drivers/video/omap2/dss/wb.c
+ * Copyright (C) 2009 Texas Instruments
+ * Author: mythripk <mythripk@ti.com>
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "WRITEBACK"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <plat/display.h>
+#include <plat/cpu.h>
+
+#include "dss.h"
+
+static struct list_head wb_list;
+
+static struct attribute *writeback_sysfs_attrs[] = {
+ NULL
+};
+
+static ssize_t writeback_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+return 0;
+}
+
+static ssize_t writeback_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+return 0;
+}
+
+static struct sysfs_ops writeback_sysfs_ops = {
+ .show = writeback_attr_show,
+ .store = writeback_attr_store,
+};
+
+static struct kobj_type writeback_ktype = {
+ .sysfs_ops = &writeback_sysfs_ops,
+ .default_attrs = writeback_sysfs_attrs,
+};
+
+bool omap_dss_check_wb(struct writeback_cache_data *wb, int overlayId, int managerId)
+{
+ bool result = false;
+ DSSDBG("ovl=%d,mgr=%d,srcty=%d(%s),src=%d",
+ overlayId, managerId, wb->source_type,
+ wb->source_type == OMAP_WB_SOURCE_OVERLAY ? "OMAP_WB_SOURCE_OVERLAY" :
+ wb->source_type == OMAP_WB_SOURCE_MANAGER ? "OMAP_WB_SOURCE_MANAGER" : "???",
+ wb->source);
+
+ if ((wb->source_type == OMAP_WB_SOURCE_OVERLAY) &&
+ ((wb->source - 3) == overlayId))
+ result = true;
+ else if (wb->source_type == OMAP_WB_SOURCE_MANAGER) {
+ switch (wb->source) {
+ case OMAP_WB_LCD_1_MANAGER:
+ if (managerId == OMAP_DSS_CHANNEL_LCD)
+ result = true;
+ case OMAP_WB_LCD_2_MANAGER:
+ if (managerId == OMAP_DSS_CHANNEL_LCD2)
+ result = true;
+ case OMAP_WB_TV_MANAGER:
+ if (managerId == OMAP_DSS_CHANNEL_DIGIT)
+ result = true;
+ case OMAP_WB_OVERLAY0:
+ case OMAP_WB_OVERLAY1:
+ case OMAP_WB_OVERLAY2:
+ case OMAP_WB_OVERLAY3:
+ break;
+ }
+ }
+
+ return result;
+
+}
+
+static bool dss_check_wb(struct omap_writeback *wb)
+{
+ DSSDBG("srcty=%d(%s),src=%d", wb->info.source_type,
+ wb->info.source_type == OMAP_WB_SOURCE_OVERLAY ? "OMAP_WB_SOURCE_OVERLAY" :
+ wb->info.source_type == OMAP_WB_SOURCE_MANAGER ? "OMAP_WB_SOURCE_MANAGER" : "???",
+ wb->info.source);
+
+ return 0;
+}
+
+static int omap_dss_wb_set_info(struct omap_writeback *wb,
+ struct omap_writeback_info *info)
+{
+ int r;
+ struct omap_writeback_info old_info;
+ old_info = wb->info;
+ wb->info = *info;
+
+ r = dss_check_wb(wb);
+ if (r) {
+ wb->info = old_info;
+ return r;
+ }
+
+ wb->info_dirty = true;
+
+ return 0;
+}
+
+static void omap_dss_wb_get_info(struct omap_writeback *wb,
+ struct omap_writeback_info *info)
+{
+ *info = wb->info;
+}
+
+struct omap_writeback *omap_dss_get_wb(int num)
+{
+ int i = 0;
+ struct omap_writeback *wb;
+
+ list_for_each_entry(wb, &wb_list, list) {
+ if (i++ == num)
+ return wb;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(omap_dss_get_wb);
+
+
+static void omap_dss_add_wb(struct omap_writeback *wb)
+{
+ list_add_tail(&wb->list, &wb_list);
+}
+
+
+void dss_init_writeback(struct platform_device *pdev)
+{
+ int r;
+ struct omap_writeback *wb;
+ INIT_LIST_HEAD(&wb_list);
+
+ wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+
+ BUG_ON(wb == NULL);
+
+ wb->check_wb = &dss_check_wb;
+ wb->set_wb_info = &omap_dss_wb_set_info;
+ wb->get_wb_info = &omap_dss_wb_get_info;
+ mutex_init(&wb->lock);
+
+ omap_dss_add_wb(wb);
+
+ r = kobject_init_and_add(&wb->kobj, &writeback_ktype,
+ &pdev->dev.kobj, "writeback", 0);
+
+ if (r) {
+ DSSERR("failed to create sysfs file\n");
+ }
+
+}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 43496d6c377f..f186c2b6509b 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -1,17 +1,16 @@
menuconfig FB_OMAP2
- tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
+ tristate "OMAP2/3/4 frame buffer support (EXPERIMENTAL)"
depends on FB && OMAP2_DSS
select OMAP2_VRAM
- select OMAP2_VRFB
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
- Frame buffer driver for OMAP2/3 based boards.
+ Frame buffer driver for OMAP2/3/4 based boards.
config FB_OMAP2_DEBUG_SUPPORT
- bool "Debug support for OMAP2/3 FB"
+ bool "Debug support for OMAP2/3/4 FB"
default y
depends on FB_OMAP2
help
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 1ffa760b8545..9c7361871d78 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -183,13 +183,14 @@ int omapfb_update_window(struct fb_info *fbi,
struct omapfb2_device *fbdev = ofbi->fbdev;
int r;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
r = omapfb_update_window_nolock(fbi, x, y, w, h);
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return r;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 4b4506da96da..34bacdd75742 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -33,6 +33,7 @@
#include <plat/display.h>
#include <plat/vram.h>
#include <plat/vrfb.h>
+#include <mach/tiler.h>
#include "omapfb.h"
@@ -44,6 +45,7 @@
static char *def_mode;
static char *def_vram;
static int def_vrfb;
+static int def_tiler;
static int def_rotate;
static int def_mirror;
@@ -621,13 +623,16 @@ void set_fb_fix(struct fb_info *fbi)
}
fix->smem_len = var->yres_virtual * fix->line_length;
- } else {
+ } else if (ofbi->rotation_type != OMAP_DSS_ROT_TILER) {
fix->line_length =
(var->xres_virtual * var->bits_per_pixel) >> 3;
- fix->smem_len = rg->size;
+
+ /* tiler line length is set during allocation, and cannot
+ be changed */
}
fix->smem_start = omapfb_get_region_paddr(ofbi);
+ fix->smem_len = rg->size;
fix->type = FB_TYPE_PACKED_PIXELS;
@@ -853,14 +858,21 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
posx, posy, outw, outh);
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ xres = var->xres;
+ yres = var->yres;
+ } else {
if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
xres = var->yres;
yres = var->xres;
} else {
xres = var->xres;
yres = var->yres;
+ }
}
+ offset = ((var->yoffset * var->xres_virtual +
+ var->xoffset) * var->bits_per_pixel) >> 3;
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
@@ -913,7 +925,12 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
info.paddr = data_start_p;
info.vaddr = data_start_v;
info.screen_width = screen_width;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ info.width =
+ ((rotation == 1) | (rotation == 3)) ? yres : xres;
+ } else {
info.width = xres;
+ }
info.height = yres;
info.color_mode = mode;
info.rotation_type = ofbi->rotation_type;
@@ -922,7 +939,12 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
info.pos_x = posx;
info.pos_y = posy;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ info.out_width =
+ ((rotation == 1) | (rotation == 3)) ? outh : outw;
+ } else {
info.out_width = outw;
+ }
info.out_height = outh;
r = ovl->set_overlay_info(ovl, &info);
@@ -969,6 +991,10 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
int rotation = (var->rotate + ofbi->rotation[i]) % 4;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ outw = var->xres;
+ outh = var->yres;
+ } else {
if (rotation == FB_ROTATE_CW ||
rotation == FB_ROTATE_CCW) {
outw = var->yres;
@@ -977,9 +1003,27 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
outw = var->xres;
outh = var->yres;
}
+ }
} else {
- outw = ovl->info.out_width;
- outh = ovl->info.out_height;
+ /*sv it comes here for vid1 on fb */
+ DBG("its vid pipeline so sclaing is enabled, still\
+ we will not scale for output size,\
+ just maintain the input size");
+ int rotation = (var->rotate + ofbi->rotation[i]) % 4;
+ if (rotation == FB_ROTATE_CW ||
+ rotation == FB_ROTATE_CCW) {
+ outw = var->yres;
+ outh = var->xres;
+ } else {
+ DBG("info.out_width = %d, info.out_height = %d\
+ take care of this for vid pipeline",
+ ovl->info.out_width,
+ ovl->info.out_height);
+ /*svoutw = ovl->info.out_width;
+ outh = ovl->info.out_height;*/
+ outw = var->xres;
+ outh = var->yres;
+ }
}
if (init) {
@@ -1038,7 +1082,8 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
struct fb_var_screeninfo new_var;
- int r;
+ int r = 0;
+ struct omap_dss_device *display = fb2display(fbi);
DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
@@ -1053,6 +1098,9 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var;
r = omapfb_apply_changes(fbi, 0);
+ /* don't call panel update for OMAP4 */
+ if (!cpu_is_omap44xx() && display && display->driver->update)
+ display->driver->update(display, 0, 0, var->xres, var->yres);
return r;
}
@@ -1101,7 +1149,24 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
- vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_private_data = ofbi;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ int k = 0, p = fix->line_length;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_ops = &mmap_user_ops; /* &dmm_remap_vm_ops; */
+
+ /* we need to figure out the height of the block. */
+ for (k = 0; k < len; k += p) {
+ /* map each page of the line */
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, vma->vm_start + k,
+ off >> PAGE_SHIFT, p, vma->vm_page_prot))
+ return -EAGAIN;
+ off += 2*64*TILER_WIDTH;
+ }
+ } else {
+ vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops;
@@ -1109,6 +1174,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
+ }
/* vm_ops.open won't be called for mmap itself. */
atomic_inc(&ofbi->map_count);
return 0;
@@ -1302,9 +1368,13 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
rg = &ofbi->region;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ tiler_free(rg->paddr);
+ } else {
if (rg->paddr)
if (omap_vram_free(rg->paddr, rg->size))
dev_err(fbdev->dev, "VRAM FREE failed\n");
+ }
if (rg->vaddr)
iounmap(rg->vaddr);
@@ -1354,6 +1424,9 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
struct omapfb2_mem_region *rg;
void __iomem *vaddr;
int r;
+ u16 h = 0, w = 0;
+ unsigned long pstride;
+ size_t psize;
rg = &ofbi->region;
memset(rg, 0, sizeof(*rg));
@@ -1362,7 +1435,19 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
if (!paddr) {
DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ int err = 0xFFFFFFFF;
+ /* get width & height from line length & size */
+ w = fbi->fix.line_length /
+ (fbi->var.bits_per_pixel >> 3);
+ h = size / fbi->fix.line_length;
+ err = tiler_alloc(TILFMT_32BIT, w, h, &paddr);
+ if (err != 0x0)
+ return -ENOMEM;
+ r = 0;
+ } else {
r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
+ }
} else {
DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
ofbi->id);
@@ -1374,7 +1459,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
return -ENOMEM;
}
- if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
+ if (ofbi->rotation_type == OMAP_DSS_ROT_DMA) {
vaddr = ioremap_wc(paddr, size);
if (!vaddr) {
@@ -1382,9 +1467,17 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
omap_vram_free(paddr, size);
return -ENOMEM;
}
+ } else if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ pstride = tiler_stride(tiler_get_natural_addr(paddr));
+ psize = h * pstride;
+ vaddr = __arm_multi_strided_ioremap(1, &paddr, &psize,
+ &pstride, (unsigned long *) &fbi->fix.line_length,
+ MT_DEVICE_WC);
+ if (vaddr == NULL)
+ return -ENOMEM;
DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
- } else {
+ } else if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
r = omap_vrfb_request_ctx(&rg->vrfb);
if (r) {
dev_err(fbdev->dev, "vrfb create ctx failed\n");
@@ -1428,6 +1521,10 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
break;
}
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ fbi->var.bits_per_pixel = 32; /* always 32-bit for tiler */
+ bytespp = fbi->var.bits_per_pixel >> 3;
+ }
if (!size) {
u16 w, h;
@@ -1439,9 +1536,13 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
w * h * bytespp, size);
- } else {
- size = w * h * bytespp;
+ } else if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ /* round up width to tiler size */
+ w = ALIGN(w, PAGE_SIZE / bytespp);
+ fbi->fix.line_length = w * bytespp;
}
+ size = w * h * bytespp;
+
}
if (!size)
@@ -1595,9 +1696,9 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
}
for (i = 0; i < fbdev->num_fbs; i++) {
- /* allocate memory automatically only for fb0, or if
+ /* allocate memory automatically only for fb0, fb1 and fb2 , or if
* excplicitly defined with vram or plat data option */
- if (i == 0 || vram_sizes[i] != 0) {
+ if (i == 0 || i == 1 || i == 2 || vram_sizes[i] != 0) {
r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
vram_sizes[i], vram_paddrs[i]);
@@ -1748,9 +1849,12 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
if (display) {
u16 w, h;
int rotation = (var->rotate + ofbi->rotation[0]) % 4;
-
display->driver->get_resolution(display, &w, &h);
+ if (ofbi->rotation_type == OMAP_DSS_ROT_TILER) {
+ var->xres = w;
+ var->yres = h;
+ } else {
if (rotation == FB_ROTATE_CW ||
rotation == FB_ROTATE_CCW) {
var->xres = h;
@@ -1759,7 +1863,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
var->xres = w;
var->yres = h;
}
-
+ }
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
@@ -1872,8 +1976,14 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->id = i;
/* assign these early, so that fb alloc can use them */
- ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
- OMAP_DSS_ROT_DMA;
+ if (def_vrfb == 1)
+ ofbi->rotation_type = OMAP_DSS_ROT_VRFB;
+ else if (def_tiler == 1)
+ ofbi->rotation_type = OMAP_DSS_ROT_TILER;
+ else
+ ofbi->rotation_type = OMAP_DSS_ROT_DMA;
+
+
ofbi->mirror = def_mirror;
fbdev->num_fbs++;
@@ -2210,9 +2320,11 @@ static int omapfb_probe(struct platform_device *pdev)
if (dssdrv->set_update_mode)
dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_MANUAL);
-
- dssdrv->get_resolution(def_display, &w, &h);
- def_display->driver->update(def_display, 0, 0, w, h);
+ /* don't call panel update for OMAP4 */
+ if (!cpu_is_omap44xx()) {
+ dssdrv->get_resolution(def_display, &w, &h);
+ def_display->driver->update(def_display, 0, 0, w, h);
+ }
} else {
if (dssdrv->set_update_mode)
dssdrv->set_update_mode(def_display,
@@ -2273,6 +2385,7 @@ module_param_named(mode, def_mode, charp, 0);
module_param_named(vram, def_vram, charp, 0);
module_param_named(rotate, def_rotate, int, 0);
module_param_named(vrfb, def_vrfb, bool, 0);
+module_param_named(tiler, def_tiler, bool, 0);
module_param_named(mirror, def_mirror, bool, 0);
/* late_initcall to let panel/ctrl drivers loaded first.
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 62bb88f5c192..5179219128bd 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -57,7 +57,8 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
return -EINVAL;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
r = 0;
if (rot_type == ofbi->rotation_type)
@@ -105,7 +106,8 @@ static ssize_t store_mirror(struct device *dev,
if (mirror != 0 && mirror != 1)
return -EINVAL;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
ofbi->mirror = mirror;
@@ -137,8 +139,9 @@ static ssize_t show_overlays(struct device *dev,
ssize_t l = 0;
int t;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
for (t = 0; t < ofbi->num_overlays; t++) {
struct omap_overlay *ovl = ofbi->overlays[t];
@@ -154,8 +157,8 @@ static ssize_t show_overlays(struct device *dev,
l += snprintf(buf + l, PAGE_SIZE - l, "\n");
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return l;
}
@@ -195,8 +198,9 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
if (buf[len - 1] == '\n')
len = len - 1;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
if (len > 0) {
char *p = (char *)buf;
@@ -303,8 +307,8 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
r = count;
out:
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return r;
}
@@ -317,7 +321,8 @@ static ssize_t show_overlays_rotate(struct device *dev,
ssize_t l = 0;
int t;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
for (t = 0; t < ofbi->num_overlays; t++) {
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
@@ -345,7 +350,8 @@ static ssize_t store_overlays_rotate(struct device *dev,
if (buf[len - 1] == '\n')
len = len - 1;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
if (len > 0) {
char *p = (char *)buf;
@@ -416,7 +422,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
for (i = 0; i < ofbi->num_overlays; i++) {
if (ofbi->overlays[i]->info.enabled) {