aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-03-08 20:21:04 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-03-08 20:21:04 +0000
commit988addf82e4c03739375279de73929580a2d4a6a (patch)
tree989ae1cd4e264bbad80c65f04480486246e7b9f3 /drivers/video
parentMerge branch 'for-rmk/samsung6' of git://git.fluff.org/bjdooks/linux into devel-stable (diff)
parentMerge git://git.kernel.org/pub/scm/linux/kernel/git/amit/virtio-console (diff)
downloadlinux-dev-988addf82e4c03739375279de73929580a2d4a6a.tar.xz
linux-dev-988addf82e4c03739375279de73929580a2d4a6a.zip
Merge branch 'origin' into devel-stable
Conflicts: arch/arm/mach-mx2/devices.c arch/arm/mach-mx2/devices.h sound/soc/pxa/pxa-ssp.c
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/aty/aty128fb.c14
-rw-r--r--drivers/video/aty/atyfb_base.c10
-rw-r--r--drivers/video/aty/radeon_backlight.c6
-rw-r--r--drivers/video/backlight/88pm860x_bl.c304
-rw-r--r--drivers/video/backlight/Kconfig13
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/max8925_bl.c200
-rw-r--r--drivers/video/console/Kconfig1
-rw-r--r--drivers/video/console/fbcon.c18
-rw-r--r--drivers/video/console/vgacon.c2
-rw-r--r--drivers/video/efifb.c11
-rw-r--r--drivers/video/fbmem.c1
-rw-r--r--drivers/video/fsl-diu-fb.c5
-rw-r--r--drivers/video/macfb.c736
-rw-r--r--drivers/video/macmodes.c80
-rw-r--r--drivers/video/omap/lcd_ams_delta.c93
-rw-r--r--drivers/video/omap/omapfb_main.c7
-rw-r--r--drivers/video/omap2/displays/Kconfig18
-rw-r--r--drivers/video/omap2/displays/Makefile3
-rw-r--r--drivers/video/omap2/displays/panel-generic.c56
-rw-r--r--drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c159
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c77
-rw-r--r--drivers/video/omap2/displays/panel-taal.c253
-rw-r--r--drivers/video/omap2/displays/panel-toppoly-tdo35s.c154
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c528
-rw-r--r--drivers/video/omap2/dss/Kconfig26
-rw-r--r--drivers/video/omap2/dss/core.c117
-rw-r--r--drivers/video/omap2/dss/dispc.c42
-rw-r--r--drivers/video/omap2/dss/display.c119
-rw-r--r--drivers/video/omap2/dss/dpi.c144
-rw-r--r--drivers/video/omap2/dss/dsi.c1031
-rw-r--r--drivers/video/omap2/dss/dss.c42
-rw-r--r--drivers/video/omap2/dss/dss.h23
-rw-r--r--drivers/video/omap2/dss/manager.c48
-rw-r--r--drivers/video/omap2/dss/overlay.c2
-rw-r--r--drivers/video/omap2/dss/rfbi.c321
-rw-r--r--drivers/video/omap2/dss/sdi.c115
-rw-r--r--drivers/video/omap2/dss/venc.c296
-rw-r--r--drivers/video/omap2/omapfb/Kconfig11
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c68
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c133
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h9
-rw-r--r--drivers/video/pvr2fb.c2
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c88
-rw-r--r--drivers/video/sunxvr500.c1
-rw-r--r--drivers/video/valkyriefb.c6
-rw-r--r--drivers/video/valkyriefb.h31
47 files changed, 3149 insertions, 2277 deletions
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index e4e4d433b007..9ee67d6da710 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1931,22 +1931,22 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
* PowerMac2,2 summer 2000 iMacs
* PowerMac4,1 january 2001 iMacs "flower power"
*/
- if (machine_is_compatible("PowerMac2,1") ||
- machine_is_compatible("PowerMac2,2") ||
- machine_is_compatible("PowerMac4,1"))
+ if (of_machine_is_compatible("PowerMac2,1") ||
+ of_machine_is_compatible("PowerMac2,2") ||
+ of_machine_is_compatible("PowerMac4,1"))
default_vmode = VMODE_1024_768_75;
/* iBook SE */
- if (machine_is_compatible("PowerBook2,2"))
+ if (of_machine_is_compatible("PowerBook2,2"))
default_vmode = VMODE_800_600_60;
/* PowerBook Firewire (Pismo), iBook Dual USB */
- if (machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook4,1"))
+ if (of_machine_is_compatible("PowerBook3,1") ||
+ of_machine_is_compatible("PowerBook4,1"))
default_vmode = VMODE_1024_768_60;
/* PowerBook Titanium */
- if (machine_is_compatible("PowerBook3,2"))
+ if (of_machine_is_compatible("PowerBook3,2"))
default_vmode = VMODE_1152_768_60;
if (default_cmode > 16)
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 1ddeb4c34763..e45ab8db2ddc 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2439,7 +2439,7 @@ static int __devinit aty_init(struct fb_info *info)
* The Apple iBook1 uses non-standard memory frequencies.
* We detect it and set the frequency manually.
*/
- if (machine_is_compatible("PowerBook2,1")) {
+ if (of_machine_is_compatible("PowerBook2,1")) {
par->pll_limits.mclk = 70;
par->pll_limits.xclk = 53;
}
@@ -2659,7 +2659,7 @@ static int __devinit aty_init(struct fb_info *info)
FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_PMAC_BACKLIGHT
- if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
+ if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) {
/*
* these bits let the 101 powerbook
* wake up from sleep -- paulus
@@ -2690,9 +2690,9 @@ static int __devinit aty_init(struct fb_info *info)
if (M64_HAS(G3_PB_1024x768))
/* G3 PowerBook with 1024x768 LCD */
default_vmode = VMODE_1024_768_60;
- else if (machine_is_compatible("iMac"))
+ else if (of_machine_is_compatible("iMac"))
default_vmode = VMODE_1024_768_75;
- else if (machine_is_compatible("PowerBook2,1"))
+ else if (of_machine_is_compatible("PowerBook2,1"))
/* iBook with 800x600 LCD */
default_vmode = VMODE_800_600_60;
else
@@ -3104,7 +3104,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
dp = pci_device_to_OF_node(pdev);
- if (node == dp->node) {
+ if (node == dp->phandle) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 1a056adb61c8..fa1198c4ccc5 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -175,9 +175,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
#ifdef CONFIG_PMAC_BACKLIGHT
pdata->negative = pdata->negative ||
- machine_is_compatible("PowerBook4,3") ||
- machine_is_compatible("PowerBook6,3") ||
- machine_is_compatible("PowerBook6,5");
+ of_machine_is_compatible("PowerBook4,3") ||
+ of_machine_is_compatible("PowerBook6,3") ||
+ of_machine_is_compatible("PowerBook6,5");
#endif
rinfo->info->bl_dev = bd;
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
new file mode 100644
index 000000000000..b8f705cca438
--- /dev/null
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -0,0 +1,304 @@
+/*
+ * Backlight driver for Marvell Semiconductor 88PM8606
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/mfd/88pm860x.h>
+
+#define MAX_BRIGHTNESS (0xFF)
+#define MIN_BRIGHTNESS (0)
+
+#define CURRENT_MASK (0x1F << 1)
+
+struct pm860x_backlight_data {
+ struct pm860x_chip *chip;
+ struct i2c_client *i2c;
+ int current_brightness;
+ int port;
+ int pwm;
+ int iset;
+};
+
+static inline int wled_a(int port)
+{
+ int ret;
+
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 2;
+ return ret;
+}
+
+static inline int wled_b(int port)
+{
+ int ret;
+
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
+ return ret;
+}
+
+/* WLED2 & WLED3 share the same IDC */
+static inline int wled_idc(int port)
+{
+ int ret;
+
+ switch (port) {
+ case PM8606_BACKLIGHT1:
+ case PM8606_BACKLIGHT2:
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
+ break;
+ case PM8606_BACKLIGHT3:
+ default:
+ ret = ((port - PM8606_BACKLIGHT2) << 1) + 3;
+ break;
+ }
+ return ret;
+}
+
+static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
+{
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+ struct pm860x_chip *chip = data->chip;
+ unsigned char value;
+ int ret;
+
+ if (brightness > MAX_BRIGHTNESS)
+ value = MAX_BRIGHTNESS;
+ else
+ value = brightness;
+
+ ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
+ if (ret < 0)
+ goto out;
+
+ if ((data->current_brightness == 0) && brightness) {
+ if (data->iset) {
+ ret = pm860x_set_bits(data->i2c, wled_idc(data->port),
+ CURRENT_MASK, data->iset);
+ if (ret < 0)
+ goto out;
+ }
+ if (data->pwm) {
+ ret = pm860x_set_bits(data->i2c, PM8606_PWM,
+ PM8606_PWM_FREQ_MASK, data->pwm);
+ if (ret < 0)
+ goto out;
+ }
+ if (brightness == MAX_BRIGHTNESS) {
+ /* set WLED_ON bit as 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, PM8606_WLED_ON);
+ }
+ } else {
+ if (brightness == MAX_BRIGHTNESS) {
+ /* set WLED_ON bit as 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, PM8606_WLED_ON);
+ } else {
+ /* clear WLED_ON bit since it's not 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, 0);
+ }
+ }
+ if (ret < 0)
+ goto out;
+
+ dev_dbg(chip->dev, "set brightness %d\n", value);
+ data->current_brightness = value;
+ return 0;
+out:
+ dev_dbg(chip->dev, "set brightness %d failure with return "
+ "value:%d\n", value, ret);
+ return ret;
+}
+
+static int pm860x_backlight_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.state & BL_CORE_SUSPENDED)
+ brightness = 0;
+
+ return pm860x_backlight_set(bl, brightness);
+}
+
+static int pm860x_backlight_get_brightness(struct backlight_device *bl)
+{
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+ struct pm860x_chip *chip = data->chip;
+ int ret;
+
+ ret = pm860x_reg_read(data->i2c, wled_a(data->port));
+ if (ret < 0)
+ goto out;
+ data->current_brightness = ret;
+ dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
+ return data->current_brightness;
+out:
+ return -EINVAL;
+}
+
+static struct backlight_ops pm860x_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = pm860x_backlight_update_status,
+ .get_brightness = pm860x_backlight_get_brightness,
+};
+
+static int __check_device(struct pm860x_backlight_pdata *pdata, char *name)
+{
+ struct pm860x_backlight_pdata *p = pdata;
+ int ret = -EINVAL;
+
+ while (p && p->id) {
+ if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0))
+ break;
+
+ if (!strncmp(name, pm860x_backlight_name[p->flags],
+ MFD_NAME_SIZE)) {
+ ret = (int)p->flags;
+ break;
+ }
+ p++;
+ }
+ return ret;
+}
+
+static int pm860x_backlight_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_platform_data *pm860x_pdata;
+ struct pm860x_backlight_pdata *pdata = NULL;
+ struct pm860x_backlight_data *data;
+ struct backlight_device *bl;
+ struct resource *res;
+ unsigned char value;
+ char name[MFD_NAME_SIZE];
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
+ return -EINVAL;
+ }
+
+ if (pdev->dev.parent->platform_data) {
+ pm860x_pdata = pdev->dev.parent->platform_data;
+ pdata = pm860x_pdata->backlight;
+ }
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data isn't assigned to "
+ "backlight\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ strncpy(name, res->name, MFD_NAME_SIZE);
+ data->chip = chip;
+ data->i2c = (chip->id == CHIP_PM8606) ? chip->client \
+ : chip->companion;
+ data->current_brightness = MAX_BRIGHTNESS;
+ data->pwm = pdata->pwm;
+ data->iset = pdata->iset;
+ data->port = __check_device(pdata, name);
+ if (data->port < 0) {
+ dev_err(&pdev->dev, "wrong platform data is assigned");
+ return -EINVAL;
+ }
+
+ bl = backlight_device_register(name, &pdev->dev, data,
+ &pm860x_backlight_ops);
+ if (IS_ERR(bl)) {
+ dev_err(&pdev->dev, "failed to register backlight\n");
+ kfree(data);
+ return PTR_ERR(bl);
+ }
+ bl->props.max_brightness = MAX_BRIGHTNESS;
+ bl->props.brightness = MAX_BRIGHTNESS;
+
+ platform_set_drvdata(pdev, bl);
+
+ /* Enable reference VSYS */
+ ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
+ if (ret < 0)
+ goto out;
+ if ((ret & PM8606_VSYS_EN) == 0) {
+ value = ret | PM8606_VSYS_EN;
+ ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
+ if (ret < 0)
+ goto out;
+ }
+ /* Enable reference OSC */
+ ret = pm860x_reg_read(data->i2c, PM8606_MISC);
+ if (ret < 0)
+ goto out;
+ if ((ret & PM8606_MISC_OSC_EN) == 0) {
+ value = ret | PM8606_MISC_OSC_EN;
+ ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
+ if (ret < 0)
+ goto out;
+ }
+ /* read current backlight */
+ ret = pm860x_backlight_get_brightness(bl);
+ if (ret < 0)
+ goto out;
+
+ backlight_update_status(bl);
+ return 0;
+out:
+ kfree(data);
+ return ret;
+}
+
+static int pm860x_backlight_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+
+ backlight_device_unregister(bl);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver pm860x_backlight_driver = {
+ .driver = {
+ .name = "88pm860x-backlight",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_backlight_probe,
+ .remove = pm860x_backlight_remove,
+};
+
+static int __init pm860x_backlight_init(void)
+{
+ return platform_driver_register(&pm860x_backlight_driver);
+}
+module_init(pm860x_backlight_init);
+
+static void __exit pm860x_backlight_exit(void)
+{
+ platform_driver_unregister(&pm860x_backlight_driver);
+}
+module_exit(pm860x_backlight_exit);
+
+MODULE_DESCRIPTION("Backlight Driver for Marvell Semiconductor 88PM8606");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-backlight");
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 09bfa9662e4d..0c77fc610212 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -212,6 +212,13 @@ config BACKLIGHT_DA903X
If you have a LCD backlight connected to the WLED output of DA9030
or DA9034 WLED output, say Y here to enable this driver.
+config BACKLIGHT_MAX8925
+ tristate "Backlight driver for MAX8925"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925
+ help
+ If you have a LCD backlight connected to the WLED output of MAX8925
+ WLED output, say Y here to enable this driver.
+
config BACKLIGHT_MBP_NVIDIA
tristate "MacBook Pro Nvidia Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86
@@ -262,3 +269,9 @@ config BACKLIGHT_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520_bl.
+config BACKLIGHT_88PM860X
+ tristate "Backlight Driver for 88PM8606 using WLED"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X
+ help
+ Say Y to enable the backlight driver for Marvell 88PM8606.
+
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 9a405548874c..6c704d41462d 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -22,10 +22,12 @@ obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
+obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
new file mode 100644
index 000000000000..c267069a52a3
--- /dev/null
+++ b/drivers/video/backlight/max8925_bl.c
@@ -0,0 +1,200 @@
+/*
+ * Backlight driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/mfd/max8925.h>
+
+#define MAX_BRIGHTNESS (0xff)
+#define MIN_BRIGHTNESS (0)
+
+#define LWX_FREQ(x) (((x - 601) / 100) & 0x7)
+
+struct max8925_backlight_data {
+ struct max8925_chip *chip;
+
+ int current_brightness;
+};
+
+static int max8925_backlight_set(struct backlight_device *bl, int brightness)
+{
+ struct max8925_backlight_data *data = bl_get_data(bl);
+ struct max8925_chip *chip = data->chip;
+ unsigned char value;
+ int ret;
+
+ if (brightness > MAX_BRIGHTNESS)
+ value = MAX_BRIGHTNESS;
+ else
+ value = brightness;
+
+ ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value);
+ if (ret < 0)
+ goto out;
+
+ if (!data->current_brightness && brightness)
+ /* enable WLED output */
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1);
+ else if (!brightness)
+ /* disable WLED output */
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0);
+ if (ret < 0)
+ goto out;
+ dev_dbg(chip->dev, "set brightness %d\n", value);
+ data->current_brightness = value;
+ return 0;
+out:
+ dev_dbg(chip->dev, "set brightness %d failure with return value:%d\n",
+ value, ret);
+ return ret;
+}
+
+static int max8925_backlight_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.state & BL_CORE_SUSPENDED)
+ brightness = 0;
+
+ return max8925_backlight_set(bl, brightness);
+}
+
+static int max8925_backlight_get_brightness(struct backlight_device *bl)
+{
+ struct max8925_backlight_data *data = bl_get_data(bl);
+ struct max8925_chip *chip = data->chip;
+ int ret;
+
+ ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL);
+ if (ret < 0)
+ return -EINVAL;
+ data->current_brightness = ret;
+ dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
+ return ret;
+}
+
+static struct backlight_ops max8925_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = max8925_backlight_update_status,
+ .get_brightness = max8925_backlight_get_brightness,
+};
+
+static int __devinit max8925_backlight_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_platform_data *max8925_pdata;
+ struct max8925_backlight_pdata *pdata = NULL;
+ struct max8925_backlight_data *data;
+ struct backlight_device *bl;
+ struct resource *res;
+ char name[MAX8925_NAME_SIZE];
+ unsigned char value;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
+ return -EINVAL;
+ }
+
+ if (pdev->dev.parent->platform_data) {
+ max8925_pdata = pdev->dev.parent->platform_data;
+ pdata = max8925_pdata->backlight;
+ }
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data isn't assigned to "
+ "backlight\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ strncpy(name, res->name, MAX8925_NAME_SIZE);
+ data->chip = chip;
+ data->current_brightness = 0;
+
+ bl = backlight_device_register(name, &pdev->dev, data,
+ &max8925_backlight_ops);
+ if (IS_ERR(bl)) {
+ dev_err(&pdev->dev, "failed to register backlight\n");
+ kfree(data);
+ return PTR_ERR(bl);
+ }
+ bl->props.max_brightness = MAX_BRIGHTNESS;
+ bl->props.brightness = MAX_BRIGHTNESS;
+
+ platform_set_drvdata(pdev, bl);
+
+ value = 0;
+ if (pdata->lxw_scl)
+ value |= (1 << 7);
+ if (pdata->lxw_freq)
+ value |= (LWX_FREQ(pdata->lxw_freq) << 4);
+ if (pdata->dual_string)
+ value |= (1 << 1);
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value);
+ if (ret < 0)
+ goto out;
+
+ backlight_update_status(bl);
+ return 0;
+out:
+ kfree(data);
+ return ret;
+}
+
+static int __devexit max8925_backlight_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct max8925_backlight_data *data = bl_get_data(bl);
+
+ backlight_device_unregister(bl);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver max8925_backlight_driver = {
+ .driver = {
+ .name = "max8925-backlight",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_backlight_probe,
+ .remove = __devexit_p(max8925_backlight_remove),
+};
+
+static int __init max8925_backlight_init(void)
+{
+ return platform_driver_register(&max8925_backlight_driver);
+}
+module_init(max8925_backlight_init);
+
+static void __exit max8925_backlight_exit(void)
+{
+ platform_driver_unregister(&max8925_backlight_driver);
+};
+module_exit(max8925_backlight_exit);
+
+MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8925-backlight");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fc7d9bbb548c..8e8f18d29d7a 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -37,6 +37,7 @@ config VGACON_SOFT_SCROLLBACK
config VGACON_SOFT_SCROLLBACK_SIZE
int "Scrollback Buffer Size (in KB)"
depends on VGACON_SOFT_SCROLLBACK
+ range 1 1024
default "64"
help
Enter the amount of System RAM to allocate for the scrollback
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3681c6a88212..b0a3fa00706d 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3025,6 +3025,20 @@ static int fbcon_fb_unregistered(struct fb_info *info)
return 0;
}
+static void fbcon_remap_all(int idx)
+{
+ int i;
+ for (i = first_fb_vc; i <= last_fb_vc; i++)
+ set_con2fb_map(i, idx, 0);
+
+ if (con_is_bound(&fb_con)) {
+ printk(KERN_INFO "fbcon: Remapping primary device, "
+ "fb%i, to tty %i-%i\n", idx,
+ first_fb_vc + 1, last_fb_vc + 1);
+ info_idx = idx;
+ }
+}
+
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
static void fbcon_select_primary(struct fb_info *info)
{
@@ -3225,6 +3239,10 @@ static int fbcon_event_notify(struct notifier_block *self,
caps = event->data;
fbcon_get_requirement(info, caps);
break;
+ case FB_EVENT_REMAP_ALL_CONSOLE:
+ idx = info->node;
+ fbcon_remap_all(idx);
+ break;
}
done:
return ret;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index cc4bbbe44aca..182dd6f8aadd 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -112,7 +112,7 @@ static int vga_video_font_height;
static int vga_scan_lines __read_mostly;
static unsigned int vga_rolled_over;
-int vgacon_text_mode_force = 0;
+static int vgacon_text_mode_force;
bool vgacon_text_force(void)
{
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index eb12182b2059..d25df51bb0d2 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -161,8 +161,17 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static void efifb_destroy(struct fb_info *info)
+{
+ if (info->screen_base)
+ iounmap(info->screen_base);
+ release_mem_region(info->aperture_base, info->aperture_size);
+ framebuffer_release(info);
+}
+
static struct fb_ops efifb_ops = {
.owner = THIS_MODULE,
+ .fb_destroy = efifb_destroy,
.fb_setcolreg = efifb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
@@ -281,7 +290,7 @@ static int __init efifb_probe(struct platform_device *dev)
info->par = NULL;
info->aperture_base = efifb_fix.smem_start;
- info->aperture_size = size_total;
+ info->aperture_size = size_remap;
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
if (!info->screen_base) {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 99bbd282ce63..a15b44e9c003 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1513,7 +1513,6 @@ register_framebuffer(struct fb_info *fb_info)
fb_info->fix.id,
registered_fb[i]->fix.id);
unregister_framebuffer(registered_fb[i]);
- break;
}
}
}
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 72d68b3dc478..4637bcbe03a4 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1633,6 +1633,11 @@ static int __init fsl_diu_setup(char *options)
#endif
static struct of_device_id fsl_diu_match[] = {
+#ifdef CONFIG_PPC_MPC512x
+ {
+ .compatible = "fsl,mpc5121-diu",
+ },
+#endif
{
.compatible = "fsl,diu",
},
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index d66887e8cbb1..43207cc6cc19 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -1,29 +1,33 @@
-/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
- don't know how to set */
-
-/* (c) 1999 David Huggins-Daines <dhd@debian.org>
-
- Primarily based on vesafb.c, by Gerd Knorr
- (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
-
- Also uses information and code from:
-
- The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
- Mellinger, Mikael Forselius, Michael Schmitz, and others.
-
- valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
- Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
-
- This code is free software. You may copy, modify, and distribute
- it subject to the terms and conditions of the GNU General Public
- License, version 2, or any later version, at your convenience. */
+/*
+ * macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
+ * don't know how to set.
+ *
+ * (c) 1999 David Huggins-Daines <dhd@debian.org>
+ *
+ * Primarily based on vesafb.c, by Gerd Knorr
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * Also uses information and code from:
+ *
+ * The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
+ * Mellinger, Mikael Forselius, Michael Schmitz, and others.
+ *
+ * valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
+ * Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
+ *
+ * The VideoToolbox "Bugs" web page at
+ * http://rajsky.psych.nyu.edu/Tips/VideoBugs.html
+ *
+ * This code is free software. You may copy, modify, and distribute
+ * it subject to the terms and conditions of the GNU General Public
+ * License, version 2, or any later version, at your convenience.
+ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/nubus.h>
#include <linux/init.h>
@@ -31,9 +35,6 @@
#include <asm/setup.h>
#include <asm/bootinfo.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
#include <asm/macintosh.h>
#include <asm/io.h>
@@ -44,7 +45,7 @@
#define DAFB_BASE 0xf9800200
/* Address for the built-in Civic framebuffer in Quadra AVs */
-#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */
+#define CIVIC_BASE 0x50f30800
/* GSC (Gray Scale Controller) base address */
#define GSC_BASE 0x50F20000
@@ -52,37 +53,9 @@
/* CSC (Color Screen Controller) base address */
#define CSC_BASE 0x50F20000
-static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info) = NULL;
-static int valkyrie_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info);
-static int dafb_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int rbv_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int mdc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int toby_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int civic_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int csc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-
-static struct {
- unsigned char addr;
- /* Note: word-aligned */
- char pad[3];
- unsigned char lut;
-} __iomem *valkyrie_cmap_regs;
+static int (*macfb_setpalette)(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info);
static struct {
unsigned char addr;
@@ -116,15 +89,15 @@ static struct {
} __iomem *civic_cmap_regs;
static struct {
- char pad1[0x40];
- unsigned char clut_waddr; /* 0x40 */
- char pad2;
- unsigned char clut_data; /* 0x42 */
- char pad3[0x3];
- unsigned char clut_raddr; /* 0x46 */
+ char pad1[0x40];
+ unsigned char clut_waddr; /* 0x40 */
+ char pad2;
+ unsigned char clut_data; /* 0x42 */
+ char pad3[0x3];
+ unsigned char clut_raddr; /* 0x46 */
} __iomem *csc_cmap_regs;
-/* We will leave these the way they are for the time being */
+/* The registers in these structs are in NuBus slot space */
struct mdc_cmap_regs {
char pad1[0x200200];
unsigned char addr;
@@ -145,13 +118,10 @@ struct jet_cmap_regs {
unsigned char lut;
};
-#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
-
-/* mode */
-static int video_slot = 0;
+#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
static struct fb_var_screeninfo macfb_defined = {
- .bits_per_pixel = 8,
+ .bits_per_pixel = 8,
.activate = FB_ACTIVATE_NOW,
.width = -1,
.height = -1,
@@ -167,181 +137,152 @@ static struct fb_fix_screeninfo macfb_fix = {
.accel = FB_ACCEL_NONE,
};
+static void *slot_addr;
static struct fb_info fb_info;
static u32 pseudo_palette[16];
-static int inverse = 0;
-static int vidtest = 0;
+static int inverse;
+static int vidtest;
-static int valkyrie_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
-{
- unsigned long flags;
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
-
- local_irq_save(flags);
-
- /* tell clut which address to fill */
- nubus_writeb(regno, &valkyrie_cmap_regs->addr);
- nop();
-
- /* send one color channel at a time */
- nubus_writeb(red, &valkyrie_cmap_regs->lut);
- nop();
- nubus_writeb(green, &valkyrie_cmap_regs->lut);
- nop();
- nubus_writeb(blue, &valkyrie_cmap_regs->lut);
-
- local_irq_restore(flags);
- return 0;
-}
-
-/* Unlike the Valkyrie, the DAFB cannot set individual colormap
- registers. Therefore, we do what the MacOS driver does (no
- kidding!) and simply set them one by one until we hit the one we
- want. */
-static int dafb_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+/*
+ * Unlike the Valkyrie, the DAFB cannot set individual colormap
+ * registers. Therefore, we do what the MacOS driver does (no
+ * kidding!) and simply set them one by one until we hit the one we
+ * want.
+ */
+static int dafb_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- /* FIXME: really, really need to use ioremap() here,
- phys_to_virt() doesn't work anymore */
static int lastreg = -1;
unsigned long flags;
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
local_irq_save(flags);
-
- /* fbdev will set an entire colourmap, but X won't. Hopefully
- this should accommodate both of them */
- if (regno != lastreg+1) {
+
+ /*
+ * fbdev will set an entire colourmap, but X won't. Hopefully
+ * this should accommodate both of them
+ */
+ if (regno != lastreg + 1) {
int i;
-
+
/* Stab in the dark trying to reset the CLUT pointer */
nubus_writel(0, &dafb_cmap_regs->reset);
nop();
-
+
/* Loop until we get to the register we want */
for (i = 0; i < regno; i++) {
- nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.red[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
- nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.green[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
- nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.blue[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
}
}
-
+
nubus_writeb(red, &dafb_cmap_regs->lut);
nop();
nubus_writeb(green, &dafb_cmap_regs->lut);
nop();
nubus_writeb(blue, &dafb_cmap_regs->lut);
-
+
local_irq_restore(flags);
lastreg = regno;
return 0;
}
/* V8 and Brazil seem to use the same DAC. Sonora does as well. */
-static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int v8_brazil_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
unsigned int bpp = info->var.bits_per_pixel;
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno;
unsigned long flags;
- if (bpp > 8) return 1; /* failsafe */
+ if (bpp > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
/* On these chips, the CLUT register numbers are spread out
- across the register space. Thus:
-
- In 8bpp, all regnos are valid.
-
- In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
-
- In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
- _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
- nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+ * across the register space. Thus:
+ * In 8bpp, all regnos are valid.
+ * In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
+ * In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff
+ */
+ regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+ nubus_writeb(regno, &v8_brazil_cmap_regs->addr);
+ nop();
/* send one color channel at a time */
- nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
- nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
- nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
+ nubus_writeb(red, &v8_brazil_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &v8_brazil_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &v8_brazil_cmap_regs->lut);
- local_irq_restore(flags);
+ local_irq_restore(flags);
return 0;
}
-static int rbv_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+/* RAM-Based Video */
+static int rbv_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- /* use MSBs */
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno;
unsigned long flags;
- if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
+ if (info->var.bits_per_pixel > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
-
+
/* From the VideoToolbox driver. Seems to be saying that
* regno #254 and #255 are the important ones for 1-bit color,
* regno #252-255 are the important ones for 2-bit color, etc.
*/
- _regno = regno + (256-(1 << info->var.bits_per_pixel));
+ regno += 256 - (1 << info->var.bits_per_pixel);
/* reset clut? (VideoToolbox sez "not necessary") */
- nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
-
+ nubus_writeb(0xFF, &rbv_cmap_regs->cntl);
+ nop();
+
/* tell clut which address to use. */
- nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
-
+ nubus_writeb(regno, &rbv_cmap_regs->addr);
+ nop();
+
/* send one color channel at a time. */
- nubus_writeb(_red, &rbv_cmap_regs->lut); nop();
- nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
- nubus_writeb(_blue, &rbv_cmap_regs->lut);
-
- local_irq_restore(flags); /* done. */
+ nubus_writeb(red, &rbv_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &rbv_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &rbv_cmap_regs->lut);
+
+ local_irq_restore(flags);
return 0;
}
-/* Macintosh Display Card (8x24) */
+/* Macintosh Display Card (8*24) */
static int mdc_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
struct fb_info *info)
{
- volatile struct mdc_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
- /* use MSBs */
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno=regno;
+ struct mdc_cmap_regs *cmap_regs = slot_addr;
unsigned long flags;
local_irq_save(flags);
-
+
/* the nop's are there to order writes. */
- nubus_writeb(_regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -350,24 +291,26 @@ static int mdc_setpalette(unsigned int regno, unsigned int red,
/* Toby frame buffer */
static int toby_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
- struct fb_info *info)
+ struct fb_info *info)
{
- volatile struct toby_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
+ struct toby_cmap_regs *cmap_regs = slot_addr;
unsigned int bpp = info->var.bits_per_pixel;
- /* use MSBs */
- unsigned char _red =~(red>>8);
- unsigned char _green=~(green>>8);
- unsigned char _blue =~(blue>>8);
- unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
unsigned long flags;
+ red = ~red;
+ green = ~green;
+ blue = ~blue;
+ regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+
local_irq_save(flags);
-
- nubus_writeb(_regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -378,20 +321,18 @@ static int jet_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
struct fb_info *info)
{
- volatile struct jet_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
- /* use MSBs */
- unsigned char _red = (red>>8);
- unsigned char _green = (green>>8);
- unsigned char _blue = (blue>>8);
+ struct jet_cmap_regs *cmap_regs = slot_addr;
unsigned long flags;
local_irq_save(flags);
-
- nubus_writeb(regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -400,53 +341,27 @@ static int jet_setpalette(unsigned int regno, unsigned int red,
/*
* Civic framebuffer -- Quadra AV built-in video. A chip
* called Sebastian holds the actual color palettes, and
- * apparently, there are two different banks of 512K RAM
+ * apparently, there are two different banks of 512K RAM
* which can act as separate framebuffers for doing video
* input and viewing the screen at the same time! The 840AV
- * Can add another 1MB RAM to give the two framebuffers
+ * Can add another 1MB RAM to give the two framebuffers
* 1MB RAM apiece.
- *
- * FIXME: this doesn't seem to work anymore.
*/
-static int civic_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int civic_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- static int lastreg = -1;
unsigned long flags;
int clut_status;
- if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
+ if (info->var.bits_per_pixel > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
-
- /*
- * Set the register address
- */
- nubus_writeb(regno, &civic_cmap_regs->addr); nop();
- /*
- * Wait for VBL interrupt here;
- * They're usually not enabled from Penguin, so we won't check
- */
-#if 0
- {
-#define CIVIC_VBL_OFFSET 0x120
- volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
- /* do interrupt setup stuff here? */
- *vbl = 0L; nop(); /* clear */
- *vbl = 1L; nop(); /* set */
- while (*vbl != 0L) /* wait for next vbl */
- {
- usleep(10); /* needed? */
- }
- /* do interrupt shutdown stuff here? */
- }
-#endif
+ /* Set the register address */
+ nubus_writeb(regno, &civic_cmap_regs->addr);
+ nop();
/*
* Grab a status word and do some checking;
@@ -459,39 +374,52 @@ static int civic_setpalette (unsigned int regno, unsigned int red,
#if 0
if ((clut_status & 0x000D) != 0)
{
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
}
#endif
- nubus_writeb( red, &civic_cmap_regs->lut); nop();
- nubus_writeb(green, &civic_cmap_regs->lut); nop();
- nubus_writeb( blue, &civic_cmap_regs->lut); nop();
- nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(red, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
}
else
{
unsigned char junk;
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
if ((clut_status & 0x000D) != 0)
{
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
}
- nubus_writeb( red, &civic_cmap_regs->lut); nop();
- nubus_writeb(green, &civic_cmap_regs->lut); nop();
- nubus_writeb( blue, &civic_cmap_regs->lut); nop();
- nubus_writeb( junk, &civic_cmap_regs->lut); nop();
+ nubus_writeb(red, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(junk, &civic_cmap_regs->lut);
}
local_irq_restore(flags);
- lastreg = regno;
return 0;
}
@@ -500,16 +428,21 @@ static int civic_setpalette (unsigned int regno, unsigned int red,
* (and the 5300 too, but that's a PowerMac). This function
* brought to you in part by the ECSC driver for MkLinux.
*/
-
-static int csc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int csc_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- mdelay(1);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ udelay(1); /* mklinux on PB 5300 waits for 260 ns */
nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
- nubus_writeb(red, &csc_cmap_regs->clut_data);
+ nubus_writeb(red, &csc_cmap_regs->clut_data);
nubus_writeb(green, &csc_cmap_regs->clut_data);
- nubus_writeb(blue, &csc_cmap_regs->clut_data);
+ nubus_writeb(blue, &csc_cmap_regs->clut_data);
+
+ local_irq_restore(flags);
return 0;
}
@@ -518,10 +451,10 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *fb_info)
{
/*
- * Set a single color register. The values supplied are
- * already rounded down to the hardware's capabilities
- * (according to the entries in the `var' structure). Return
- * != 0 for invalid regno.
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure).
+ * Return non-zero for invalid regno.
*/
if (regno >= fb_info->cmap.len)
@@ -536,8 +469,8 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
case 4:
case 8:
if (macfb_setpalette)
- macfb_setpalette(regno, red, green, blue,
- fb_info);
+ macfb_setpalette(regno, red >> 8, green >> 8,
+ blue >> 8, fb_info);
else
return 1;
break;
@@ -555,28 +488,22 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
} else {
/* 0:5:6:5 */
((u32*) (fb_info->pseudo_palette))[regno] =
- ((red & 0xf800) ) |
+ ((red & 0xf800) >> 0) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
}
break;
- /* I'm pretty sure that one or the other of these
- doesn't exist on 68k Macs */
+ /*
+ * 24-bit colour almost doesn't exist on 68k Macs --
+ * http://support.apple.com/kb/TA28634 (Old Article: 10992)
+ */
case 24:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
- (green << fb_info->var.green.offset) |
- (blue << fb_info->var.blue.offset);
- break;
case 32:
red >>= 8;
green >>= 8;
blue >>= 8;
((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
+ (red << fb_info->var.red.offset) |
(green << fb_info->var.green.offset) |
(blue << fb_info->var.blue.offset);
break;
@@ -597,25 +524,24 @@ static struct fb_ops macfb_ops = {
static void __init macfb_setup(char *options)
{
char *this_opt;
-
+
if (!options || !*options)
return;
-
+
while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
-
- if (! strcmp(this_opt, "inverse"))
- inverse=1;
- /* This means "turn on experimental CLUT code" */
- else if (!strcmp(this_opt, "vidtest"))
- vidtest=1;
+ if (!*this_opt)
+ continue;
+
+ if (!strcmp(this_opt, "inverse"))
+ inverse = 1;
+ else
+ if (!strcmp(this_opt, "vidtest"))
+ vidtest = 1; /* enable experimental CLUT code */
}
}
static void __init iounmap_macfb(void)
{
- if (valkyrie_cmap_regs)
- iounmap(valkyrie_cmap_regs);
if (dafb_cmap_regs)
iounmap(dafb_cmap_regs);
if (v8_brazil_cmap_regs)
@@ -642,48 +568,55 @@ static int __init macfb_init(void)
if (!MACH_IS_MAC)
return -ENODEV;
- /* There can only be one internal video controller anyway so
- we're not too worried about this */
+ if (mac_bi_data.id == MAC_MODEL_Q630 ||
+ mac_bi_data.id == MAC_MODEL_P588)
+ return -ENODEV; /* See valkyriefb.c */
+
macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
macfb_defined.yres = mac_bi_data.dimensions >> 16;
macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
+
macfb_fix.line_length = mac_bi_data.videorow;
- macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
+ macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
/* Note: physical address (since 2.1.127) */
- macfb_fix.smem_start = mac_bi_data.videoaddr;
- /* This is actually redundant with the initial mappings.
- However, there are some non-obvious aspects to the way
- those mappings are set up, so this is in fact the safest
- way to ensure that this driver will work on every possible
- Mac */
- fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len);
-
- printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
- macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024);
- printk("macfb: mode is %dx%dx%d, linelength=%d\n",
- macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length);
-
+ macfb_fix.smem_start = mac_bi_data.videoaddr;
+
/*
- * Fill in the available video resolution
+ * This is actually redundant with the initial mappings.
+ * However, there are some non-obvious aspects to the way
+ * those mappings are set up, so this is in fact the safest
+ * way to ensure that this driver will work on every possible Mac
*/
-
- macfb_defined.xres_virtual = macfb_defined.xres;
- macfb_defined.yres_virtual = macfb_defined.yres;
- macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
- macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
+ fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
+ macfb_fix.smem_len);
+ if (!fb_info.screen_base)
+ return -ENODEV;
- printk("macfb: scrolling: redraw\n");
+ printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
+ macfb_fix.smem_start, fb_info.screen_base,
+ macfb_fix.smem_len / 1024);
+ printk("macfb: mode is %dx%dx%d, linelength=%d\n",
+ macfb_defined.xres, macfb_defined.yres,
+ macfb_defined.bits_per_pixel, macfb_fix.line_length);
+
+ /* Fill in the available video resolution */
+ macfb_defined.xres_virtual = macfb_defined.xres;
macfb_defined.yres_virtual = macfb_defined.yres;
+ macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
+ macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
- /* some dummy values for timing to make fbset happy */
- macfb_defined.pixclock = 10000000 / macfb_defined.xres * 1000 / macfb_defined.yres;
+ /* Some dummy values for timing to make fbset happy */
+ macfb_defined.pixclock = 10000000 / macfb_defined.xres *
+ 1000 / macfb_defined.yres;
macfb_defined.left_margin = (macfb_defined.xres / 8) & 0xf8;
macfb_defined.hsync_len = (macfb_defined.xres / 8) & 0xf8;
switch (macfb_defined.bits_per_pixel) {
case 1:
- /* XXX: I think this will catch any program that tries
- to do FBIO_PUTCMAP when the visual is monochrome */
+ /*
+ * XXX: I think this will catch any program that tries
+ * to do FBIO_PUTCMAP when the visual is monochrome.
+ */
macfb_defined.red.length = macfb_defined.bits_per_pixel;
macfb_defined.green.length = macfb_defined.bits_per_pixel;
macfb_defined.blue.length = macfb_defined.bits_per_pixel;
@@ -708,53 +641,52 @@ static int __init macfb_init(void)
macfb_defined.green.length = 5;
macfb_defined.blue.offset = 0;
macfb_defined.blue.length = 5;
- printk("macfb: directcolor: "
- "size=1:5:5:5, shift=15:10:5:0\n");
video_cmap_len = 16;
- /* Should actually be FB_VISUAL_DIRECTCOLOR, but this
- works too */
+ /*
+ * Should actually be FB_VISUAL_DIRECTCOLOR, but this
+ * works too
+ */
macfb_fix.visual = FB_VISUAL_TRUECOLOR;
break;
case 24:
case 32:
- /* XXX: have to test these... can any 68k Macs
- actually do this on internal video? */
macfb_defined.red.offset = 16;
macfb_defined.red.length = 8;
macfb_defined.green.offset = 8;
macfb_defined.green.length = 8;
macfb_defined.blue.offset = 0;
macfb_defined.blue.length = 8;
- printk("macfb: truecolor: "
- "size=0:8:8:8, shift=0:16:8:0\n");
video_cmap_len = 16;
macfb_fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
default:
video_cmap_len = 0;
macfb_fix.visual = FB_VISUAL_MONO01;
- printk("macfb: unknown or unsupported bit depth: %d\n", macfb_defined.bits_per_pixel);
+ printk("macfb: unknown or unsupported bit depth: %d\n",
+ macfb_defined.bits_per_pixel);
break;
}
- /* Hardware dependent stuff */
- /* We take a wild guess that if the video physical address is
- * in nubus slot space, that the nubus card is driving video.
- * Penguin really ought to tell us whether we are using internal
- * video or not.
+ /*
+ * We take a wild guess that if the video physical address is
+ * in nubus slot space, that the nubus card is driving video.
+ * Penguin really ought to tell us whether we are using internal
+ * video or not.
+ * Hopefully we only find one of them. Otherwise our NuBus
+ * code is really broken :-)
*/
- /* Hopefully we only find one of them. Otherwise our NuBus
- code is really broken :-) */
- while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
- != NULL)
+ while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY,
+ NUBUS_TYPE_VIDEO, ndev)))
{
- if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
- && (mac_bi_data.videoaddr <
- (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+ unsigned long base = ndev->board->slot_addr;
+
+ if (mac_bi_data.videoaddr < base ||
+ mac_bi_data.videoaddr - base > 0xFFFFFF)
continue;
+
video_is_nubus = 1;
- /* We should probably just use the slot address... */
- video_slot = ndev->board->slot;
+ slot_addr = (unsigned char *)base;
switch(ndev->dr_hw) {
case NUBUS_DRHW_APPLE_MDC:
@@ -771,7 +703,7 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "Jet");
macfb_setpalette = jet_setpalette;
macfb_defined.activate = FB_ACTIVATE_NOW;
- break;
+ break;
default:
strcpy(macfb_fix.id, "Generic NuBus");
break;
@@ -779,30 +711,19 @@ static int __init macfb_init(void)
}
/* If it's not a NuBus card, it must be internal video */
- /* FIXME: this function is getting way too big. (this driver
- is too...) */
if (!video_is_nubus)
- switch( mac_bi_data.id )
- {
- /* Valkyrie Quadras */
- case MAC_MODEL_Q630:
- /* I'm not sure about this one */
- case MAC_MODEL_P588:
- strcpy(macfb_fix.id, "Valkyrie");
- macfb_setpalette = valkyrie_setpalette;
- macfb_defined.activate = FB_ACTIVATE_NOW;
- valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
- break;
-
- /* DAFB Quadras */
- /* Note: these first four have the v7 DAFB, which is
- known to be rather unlike the ones used in the
- other models */
+ switch (mac_bi_data.id) {
+ /*
+ * DAFB Quadras
+ * Note: these first four have the v7 DAFB, which is
+ * known to be rather unlike the ones used in the
+ * other models
+ */
case MAC_MODEL_P475:
case MAC_MODEL_P475F:
case MAC_MODEL_P575:
case MAC_MODEL_Q605:
-
+
case MAC_MODEL_Q800:
case MAC_MODEL_Q650:
case MAC_MODEL_Q610:
@@ -817,17 +738,21 @@ static int __init macfb_init(void)
dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
break;
- /* LC II uses the V8 framebuffer */
+ /*
+ * LC II uses the V8 framebuffer
+ */
case MAC_MODEL_LCII:
strcpy(macfb_fix.id, "V8");
macfb_setpalette = v8_brazil_setpalette;
macfb_defined.activate = FB_ACTIVATE_NOW;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
-
- /* IIvi, IIvx use the "Brazil" framebuffer (which is
- very much like the V8, it seems, and probably uses
- the same DAC) */
+
+ /*
+ * IIvi, IIvx use the "Brazil" framebuffer (which is
+ * very much like the V8, it seems, and probably uses
+ * the same DAC)
+ */
case MAC_MODEL_IIVI:
case MAC_MODEL_IIVX:
case MAC_MODEL_P600:
@@ -836,12 +761,14 @@ static int __init macfb_init(void)
macfb_defined.activate = FB_ACTIVATE_NOW;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
-
- /* LC III (and friends) use the Sonora framebuffer */
- /* Incidentally this is also used in the non-AV models
- of the x100 PowerMacs */
- /* These do in fact seem to use the same DAC interface
- as the LC II. */
+
+ /*
+ * LC III (and friends) use the Sonora framebuffer
+ * Incidentally this is also used in the non-AV models
+ * of the x100 PowerMacs
+ * These do in fact seem to use the same DAC interface
+ * as the LC II.
+ */
case MAC_MODEL_LCIII:
case MAC_MODEL_P520:
case MAC_MODEL_P550:
@@ -852,9 +779,11 @@ static int __init macfb_init(void)
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
- /* IIci and IIsi use the infamous RBV chip
- (the IIsi is just a rebadged and crippled
- IIci in a different case, BTW) */
+ /*
+ * IIci and IIsi use the infamous RBV chip
+ * (the IIsi is just a rebadged and crippled
+ * IIci in a different case, BTW)
+ */
case MAC_MODEL_IICI:
case MAC_MODEL_IISI:
macfb_setpalette = rbv_setpalette;
@@ -863,7 +792,9 @@ static int __init macfb_init(void)
rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
- /* AVs use the Civic framebuffer */
+ /*
+ * AVs use the Civic framebuffer
+ */
case MAC_MODEL_Q840:
case MAC_MODEL_C660:
macfb_setpalette = civic_setpalette;
@@ -873,15 +804,10 @@ static int __init macfb_init(void)
break;
- /* Write a setpalette function for your machine, then
- you can add something similar here. These are
- grouped by classes of video chipsets. Some of this
- information is from the VideoToolbox "Bugs" web
- page at
- http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
-
- /* Assorted weirdos */
- /* We think this may be like the LC II */
+ /*
+ * Assorted weirdos
+ * We think this may be like the LC II
+ */
case MAC_MODEL_LC:
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
@@ -891,7 +817,10 @@ static int __init macfb_init(void)
}
strcpy(macfb_fix.id, "LC");
break;
- /* We think this may be like the LC II */
+
+ /*
+ * We think this may be like the LC II
+ */
case MAC_MODEL_CCL:
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
@@ -902,31 +831,42 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "Color Classic");
break;
- /* And we *do* mean "weirdos" */
+ /*
+ * And we *do* mean "weirdos"
+ */
case MAC_MODEL_TV:
strcpy(macfb_fix.id, "Mac TV");
break;
- /* These don't have colour, so no need to worry */
+ /*
+ * These don't have colour, so no need to worry
+ */
case MAC_MODEL_SE30:
case MAC_MODEL_CLII:
strcpy(macfb_fix.id, "Monochrome");
break;
- /* Powerbooks are particularly difficult. Many of
- them have separate framebuffers for external and
- internal video, which is admittedly pretty cool,
- but will be a bit of a headache to support here.
- Also, many of them are grayscale, and we don't
- really support that. */
-
+ /*
+ * Powerbooks are particularly difficult. Many of
+ * them have separate framebuffers for external and
+ * internal video, which is admittedly pretty cool,
+ * but will be a bit of a headache to support here.
+ * Also, many of them are grayscale, and we don't
+ * really support that.
+ */
+
+ /*
+ * Slot 0 ROM says TIM. No external video. B&W.
+ */
case MAC_MODEL_PB140:
case MAC_MODEL_PB145:
case MAC_MODEL_PB170:
strcpy(macfb_fix.id, "DDC");
break;
- /* Internal is GSC, External (if present) is ViSC */
+ /*
+ * Internal is GSC, External (if present) is ViSC
+ */
case MAC_MODEL_PB150: /* no external video */
case MAC_MODEL_PB160:
case MAC_MODEL_PB165:
@@ -936,13 +876,17 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "GSC");
break;
- /* Internal is TIM, External is ViSC */
+ /*
+ * Internal is TIM, External is ViSC
+ */
case MAC_MODEL_PB165C:
case MAC_MODEL_PB180C:
strcpy(macfb_fix.id, "TIM");
break;
- /* Internal is CSC, External is Keystone+Ariel. */
+ /*
+ * Internal is CSC, External is Keystone+Ariel.
+ */
case MAC_MODEL_PB190: /* external video is optional */
case MAC_MODEL_PB520:
case MAC_MODEL_PB250:
@@ -954,7 +898,7 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "CSC");
csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
break;
-
+
default:
strcpy(macfb_fix.id, "Unknown");
break;
@@ -969,7 +913,7 @@ static int __init macfb_init(void)
err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
if (err)
goto fail_unmap;
-
+
err = register_framebuffer(&fb_info);
if (err)
goto fail_dealloc;
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index 083f60321ed8..af86c081d2be 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -33,6 +33,10 @@
static const struct fb_videomode mac_modedb[] = {
{
+ /* 512x384, 60Hz, Non-Interlaced (15.67 MHz dot clock) */
+ "mac2", 60, 512, 384, 63828, 80, 16, 19, 1, 32, 3,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
"mac5", 60, 640, 480, 39722, 32, 32, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED
@@ -41,6 +45,10 @@ static const struct fb_videomode mac_modedb[] = {
"mac6", 67, 640, 480, 33334, 80, 80, 39, 3, 64, 3,
0, FB_VMODE_NONINTERLACED
}, {
+ /* 640x870, 75Hz (portrait), Non-Interlaced (57.28 MHz dot clock) */
+ "mac7", 75, 640, 870, 17457, 80, 32, 42, 3, 80, 3,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
/* 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) */
"mac9", 56, 800, 600, 27778, 112, 40, 22, 1, 72, 2,
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
@@ -105,10 +113,6 @@ static const struct fb_videomode mac_modedb[] = {
"mac1", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
}, {
- /* VMODE_512_384_60: 512x384, 60Hz, Non-Interlaced */
- "mac2", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
- sync, FB_VMODE_NONINTERLACED
- }, {
/* VMODE_640_480_50I: 640x480, 50Hz, Interlaced (PAL) */
"mac3", 50, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
@@ -117,10 +121,6 @@ static const struct fb_videomode mac_modedb[] = {
"mac4", 60, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
}, {
- /* VMODE_640_870_75P: 640x870, 75Hz (portrait), Non-Interlaced */
- "mac7", 75, 640, 870, pixclock, left, right, upper, lower, hslen, vslen,
- sync, FB_VMODE_NONINTERLACED
- }, {
/* VMODE_768_576_50I: 768x576, 50Hz (PAL full frame), Interlaced */
"mac8", 50, 768, 576, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
@@ -134,38 +134,42 @@ static const struct fb_videomode mac_modedb[] = {
*
* These MUST be ordered in
* - increasing resolution
- * - decreasing refresh rate
+ * - decreasing pixel clock period
*/
static const struct mode_map {
int vmode;
const struct fb_videomode *mode;
} mac_modes[] = {
+ /* 512x384 */
+ { VMODE_512_384_60, &mac_modedb[0] },
/* 640x480 */
- { VMODE_640_480_67, &mac_modedb[1] },
- { VMODE_640_480_60, &mac_modedb[0] },
+ { VMODE_640_480_60, &mac_modedb[1] },
+ { VMODE_640_480_67, &mac_modedb[2] },
+ /* 640x870 */
+ { VMODE_640_870_75P, &mac_modedb[3] },
/* 800x600 */
- { VMODE_800_600_75, &mac_modedb[5] },
- { VMODE_800_600_72, &mac_modedb[4] },
- { VMODE_800_600_60, &mac_modedb[3] },
- { VMODE_800_600_56, &mac_modedb[2] },
+ { VMODE_800_600_56, &mac_modedb[4] },
+ { VMODE_800_600_60, &mac_modedb[5] },
+ { VMODE_800_600_75, &mac_modedb[7] },
+ { VMODE_800_600_72, &mac_modedb[6] },
/* 832x624 */
- { VMODE_832_624_75, &mac_modedb[6] },
+ { VMODE_832_624_75, &mac_modedb[8] },
/* 1024x768 */
- { VMODE_1024_768_75, &mac_modedb[10] },
- { VMODE_1024_768_75V, &mac_modedb[9] },
- { VMODE_1024_768_70, &mac_modedb[8] },
- { VMODE_1024_768_60, &mac_modedb[7] },
+ { VMODE_1024_768_60, &mac_modedb[9] },
+ { VMODE_1024_768_70, &mac_modedb[10] },
+ { VMODE_1024_768_75V, &mac_modedb[11] },
+ { VMODE_1024_768_75, &mac_modedb[12] },
/* 1152x768 */
- { VMODE_1152_768_60, &mac_modedb[14] },
+ { VMODE_1152_768_60, &mac_modedb[16] },
/* 1152x870 */
- { VMODE_1152_870_75, &mac_modedb[11] },
+ { VMODE_1152_870_75, &mac_modedb[13] },
/* 1280x960 */
- { VMODE_1280_960_75, &mac_modedb[12] },
+ { VMODE_1280_960_75, &mac_modedb[14] },
/* 1280x1024 */
- { VMODE_1280_1024_75, &mac_modedb[13] },
+ { VMODE_1280_1024_75, &mac_modedb[15] },
/* 1600x1024 */
- { VMODE_1600_1024_60, &mac_modedb[15] },
+ { VMODE_1600_1024_60, &mac_modedb[17] },
{ -1, NULL }
};
@@ -299,7 +303,6 @@ EXPORT_SYMBOL(mac_vmode_to_var);
int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
int *cmode)
{
- const struct fb_videomode *mode = NULL;
const struct mode_map *map;
if (var->bits_per_pixel <= 8)
@@ -311,8 +314,13 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
else
return -EINVAL;
+ /*
+ * Find the mac_mode with a matching resolution or failing that, the
+ * closest larger resolution. Skip modes with a shorter pixel clock period.
+ */
for (map = mac_modes; map->vmode != -1; map++) {
- mode = map->mode;
+ const struct fb_videomode *mode = map->mode;
+
if (var->xres > mode->xres || var->yres > mode->yres)
continue;
if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres)
@@ -322,6 +330,24 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
if ((var->vmode & FB_VMODE_MASK) != mode->vmode)
continue;
*vmode = map->vmode;
+
+ /*
+ * Having found a good resolution, find the matching pixel clock
+ * or failing that, the closest longer pixel clock period.
+ */
+ map++;
+ while (map->vmode != -1) {
+ const struct fb_videomode *clk_mode = map->mode;
+
+ if (mode->xres != clk_mode->xres || mode->yres != clk_mode->yres)
+ break;
+ if (var->pixclock > mode->pixclock)
+ break;
+ if (mode->vmode != clk_mode->vmode)
+ continue;
+ *vmode = map->vmode;
+ map++;
+ }
return 0;
}
return -EINVAL;
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 567db6ac32c8..6978ae4ef83a 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/lcd.h>
#include <plat/board-ams-delta.h>
#include <mach/hardware.h>
@@ -32,6 +33,71 @@
#define AMS_DELTA_DEFAULT_CONTRAST 112
+#define AMS_DELTA_MAX_CONTRAST 0x00FF
+#define AMS_DELTA_LCD_POWER 0x0100
+
+
+/* LCD class device section */
+
+static int ams_delta_lcd;
+
+static int ams_delta_lcd_set_power(struct lcd_device *dev, int power)
+{
+ if (power == FB_BLANK_UNBLANK) {
+ if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) {
+ omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST,
+ OMAP_PWL_ENABLE);
+ omap_writeb(1, OMAP_PWL_CLK_ENABLE);
+ ams_delta_lcd |= AMS_DELTA_LCD_POWER;
+ }
+ } else {
+ if (ams_delta_lcd & AMS_DELTA_LCD_POWER) {
+ omap_writeb(0, OMAP_PWL_ENABLE);
+ omap_writeb(0, OMAP_PWL_CLK_ENABLE);
+ ams_delta_lcd &= ~AMS_DELTA_LCD_POWER;
+ }
+ }
+ return 0;
+}
+
+static int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value)
+{
+ if ((value >= 0) && (value <= AMS_DELTA_MAX_CONTRAST)) {
+ omap_writeb(value, OMAP_PWL_ENABLE);
+ ams_delta_lcd &= ~AMS_DELTA_MAX_CONTRAST;
+ ams_delta_lcd |= value;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_LCD_CLASS_DEVICE
+static int ams_delta_lcd_get_power(struct lcd_device *dev)
+{
+ if (ams_delta_lcd & AMS_DELTA_LCD_POWER)
+ return FB_BLANK_UNBLANK;
+ else
+ return FB_BLANK_POWERDOWN;
+}
+
+static int ams_delta_lcd_get_contrast(struct lcd_device *dev)
+{
+ if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER))
+ return 0;
+
+ return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST;
+}
+
+static struct lcd_ops ams_delta_lcd_ops = {
+ .get_power = ams_delta_lcd_get_power,
+ .set_power = ams_delta_lcd_set_power,
+ .get_contrast = ams_delta_lcd_get_contrast,
+ .set_contrast = ams_delta_lcd_set_contrast,
+};
+#endif
+
+
+/* omapfb panel section */
+
static int ams_delta_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
{
@@ -48,10 +114,6 @@ static int ams_delta_panel_enable(struct lcd_panel *panel)
AMS_DELTA_LATCH2_LCD_NDISP);
ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
AMS_DELTA_LATCH2_LCD_VBLEN);
-
- omap_writeb(1, OMAP_PWL_CLK_ENABLE);
- omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE);
-
return 0;
}
@@ -91,8 +153,31 @@ static struct lcd_panel ams_delta_panel = {
.get_caps = ams_delta_panel_get_caps,
};
+
+/* platform driver section */
+
static int ams_delta_panel_probe(struct platform_device *pdev)
{
+ struct lcd_device *lcd_device = NULL;
+#ifdef CONFIG_LCD_CLASS_DEVICE
+ int ret;
+
+ lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL,
+ &ams_delta_lcd_ops);
+
+ if (IS_ERR(lcd_device)) {
+ ret = PTR_ERR(lcd_device);
+ dev_err(&pdev->dev, "failed to register device\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, lcd_device);
+ lcd_device->props.max_contrast = AMS_DELTA_MAX_CONTRAST;
+#endif
+
+ ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST);
+ ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK);
+
omapfb_register_panel(&ams_delta_panel);
return 0;
}
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 2c4f470fa086..8ce60e1b220a 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -486,10 +486,11 @@ static int set_color_mode(struct omapfb_plane_struct *plane,
return 0;
case 12:
var->bits_per_pixel = 16;
- plane->color_mode = OMAPFB_COLOR_RGB444;
- return 0;
case 16:
- plane->color_mode = OMAPFB_COLOR_RGB565;
+ if (plane->fbdev->panel->bpp == 12)
+ plane->color_mode = OMAPFB_COLOR_RGB444;
+ else
+ plane->color_mode = OMAPFB_COLOR_RGB565;
return 0;
default:
return -EINVAL;
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index b12a59c9c50a..dfb57ee50861 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -13,10 +13,28 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
+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_TAAL
tristate "Taal DSI Panel"
depends on OMAP2_DSS_DSI
help
Taal DSI command mode panel from TPO.
+config PANEL_TOPPOLY_TDO35S
+ tristate "Toppoly TDO35S LCD Panel support"
+ depends on OMAP2_DSS
+ help
+ LCD Panel used in CM-T35
+
+config PANEL_TPO_TD043MTEA1
+ tristate "TPO TD043MTEA1 LCD Panel"
+ depends on OMAP2_DSS && I2C
+ help
+ LCD Panel used in OMAP3 Pandora
+
endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index 955646440b3a..e2bb32168dee 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,4 +1,7 @@
obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
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_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
+obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
index eb48d1afd800..c59e4baed8b2 100644
--- a/drivers/video/omap2/displays/panel-generic.c
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -35,6 +35,35 @@ static struct omap_video_timings generic_panel_timings = {
.vbp = 7,
};
+static int generic_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void generic_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
static int generic_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT;
@@ -51,27 +80,40 @@ static int generic_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
- if (dssdev->platform_enable)
- r = dssdev->platform_enable(dssdev);
+ r = generic_panel_power_on(dssdev);
+ if (r)
+ return r;
- return r;
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
}
static void generic_panel_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ generic_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int generic_panel_suspend(struct omap_dss_device *dssdev)
{
- generic_panel_disable(dssdev);
+ generic_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int generic_panel_resume(struct omap_dss_device *dssdev)
{
- return generic_panel_enable(dssdev);
+ int r = 0;
+
+ r = generic_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
}
static struct omap_dss_driver generic_driver = {
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
new file mode 100644
index 000000000000..10267461991c
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
@@ -0,0 +1,159 @@
+/*
+ * LCD panel driver for Sharp LQ043T1DG01
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@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/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+static struct omap_video_timings sharp_lq_timings = {
+ .x_res = 480,
+ .y_res = 272,
+
+ .pixel_clock = 9000,
+
+ .hsw = 42,
+ .hfp = 3,
+ .hbp = 2,
+
+ .vsw = 11,
+ .vfp = 3,
+ .vbp = 2,
+};
+
+static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ /* wait couple of vsyncs until enabling the LCD */
+ msleep(50);
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ /* wait at least 5 vsyncs after disabling the LCD */
+ msleep(100);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
+{
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
+ dssdev->panel.acb = 0x0;
+ dssdev->panel.timings = sharp_lq_timings;
+
+ return 0;
+}
+
+static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = sharp_lq_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
+{
+ sharp_lq_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
+{
+ sharp_lq_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = sharp_lq_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static struct omap_dss_driver sharp_lq_driver = {
+ .probe = sharp_lq_panel_probe,
+ .remove = sharp_lq_panel_remove,
+
+ .enable = sharp_lq_panel_enable,
+ .disable = sharp_lq_panel_disable,
+ .suspend = sharp_lq_panel_suspend,
+ .resume = sharp_lq_panel_resume,
+
+ .driver = {
+ .name = "sharp_lq_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sharp_lq_panel_drv_init(void)
+{
+ return omap_dss_register_driver(&sharp_lq_driver);
+}
+
+static void __exit sharp_lq_panel_drv_exit(void)
+{
+ omap_dss_unregister_driver(&sharp_lq_driver);
+}
+
+module_init(sharp_lq_panel_drv_init);
+module_exit(sharp_lq_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index bbe880bbe795..8d51a5e6341c 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -20,19 +20,10 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <plat/display.h>
-struct sharp_data {
- /* XXX This regulator should actually be in SDP board file, not here,
- * as it doesn't actually power the LCD, but something else that
- * affects the output to LCD (I think. Somebody clarify). It doesn't do
- * harm here, as SDP is the only board using this currently */
- struct regulator *vdvi_reg;
-};
-
static struct omap_video_timings sharp_ls_timings = {
.x_res = 480,
.y_res = 640,
@@ -50,77 +41,81 @@ static struct omap_video_timings sharp_ls_timings = {
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd;
-
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);
-
- sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
- if (IS_ERR(sd->vdvi_reg)) {
- kfree(sd);
- pr_err("failed to get VDVI regulator\n");
- return PTR_ERR(sd->vdvi_reg);
- }
-
return 0;
}
static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
-
- regulator_put(sd->vdvi_reg);
-
- kfree(sd);
}
-static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
+static int sharp_ls_power_on(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
int r = 0;
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- regulator_enable(sd->vdvi_reg);
-
- if (dssdev->platform_enable)
+ if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
return r;
}
-static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
+static void sharp_ls_power_off(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
-
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
- regulator_disable(sd->vdvi_reg);
-
/* wait at least 5 vsyncs after disabling the LCD */
msleep(100);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+ r = sharp_ls_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
+}
+
+static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
+{
+ sharp_ls_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
{
- sharp_ls_panel_disable(dssdev);
+ sharp_ls_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
{
- return sharp_ls_panel_enable(dssdev);
+ int r;
+ r = sharp_ls_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
}
static struct omap_dss_driver sharp_ls_driver = {
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 1f01dfc5e52e..fcd6a61a91eb 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -63,6 +63,8 @@
/* #define TAAL_USE_ESD_CHECK */
#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
+static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
+
struct taal_data {
struct backlight_device *bldev;
@@ -510,15 +512,12 @@ static int taal_probe(struct omap_dss_device *dssdev)
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
- goto err2;
+ goto err1;
}
INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
dev_set_drvdata(&dssdev->dev, td);
- dssdev->get_timings = taal_get_timings;
- dssdev->get_resolution = taal_get_resolution;
-
/* if no platform set_backlight() defined, presume DSI backlight
* control */
if (!dssdev->set_backlight)
@@ -528,7 +527,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
&taal_bl_ops);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
- goto err1;
+ goto err2;
}
td->bldev = bldev;
@@ -621,14 +620,12 @@ static void taal_remove(struct omap_dss_device *dssdev)
kfree(td);
}
-static int taal_enable(struct omap_dss_device *dssdev)
+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;
- dev_dbg(&dssdev->dev, "enable\n");
-
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
@@ -638,6 +635,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
/* it seems we have to wait a bit until taal is ready */
msleep(5);
+ dsi_bus_lock();
+
+ r = omapdss_dsi_display_enable(dssdev);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable DSI\n");
+ goto err0;
+ }
+
+ omapdss_dsi_vc_enable_hs(TCH, false);
+
r = taal_sleep_out(td);
if (r)
goto err;
@@ -661,6 +668,10 @@ static int taal_enable(struct omap_dss_device *dssdev)
taal_dcs_write_0(DCS_DISPLAY_ON);
+ r = _taal_enable_te(dssdev, td->te_enabled);
+ if (r)
+ goto err;
+
#ifdef TAAL_USE_ESD_CHECK
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
#endif
@@ -676,19 +687,27 @@ static int taal_enable(struct omap_dss_device *dssdev)
td->intro_printed = true;
}
+ omapdss_dsi_vc_enable_hs(TCH, true);
+
+ dsi_bus_unlock();
+
return 0;
err:
+ dsi_bus_unlock();
+
+ omapdss_dsi_display_disable(dssdev);
+err0:
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
return r;
}
-static void taal_disable(struct omap_dss_device *dssdev)
+static void taal_power_off(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- dev_dbg(&dssdev->dev, "disable\n");
+ dsi_bus_lock();
cancel_delayed_work(&td->esd_work);
@@ -698,41 +717,124 @@ static void taal_disable(struct omap_dss_device *dssdev)
/* wait a bit so that the message goes through */
msleep(10);
+ omapdss_dsi_display_disable(dssdev);
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
td->enabled = 0;
+
+ dsi_bus_unlock();
+}
+
+static int taal_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+ dev_dbg(&dssdev->dev, "enable\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+ return -EINVAL;
+
+ r = taal_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void taal_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "disable\n");
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ taal_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int taal_suspend(struct omap_dss_device *dssdev)
{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bldev = td->bldev;
+ dev_dbg(&dssdev->dev, "suspend\n");
- bldev->props.power = FB_BLANK_POWERDOWN;
- taal_bl_update_status(bldev);
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return -EINVAL;
+
+ taal_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int taal_resume(struct omap_dss_device *dssdev)
{
+ int r;
+ dev_dbg(&dssdev->dev, "resume\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
+ return -EINVAL;
+
+ r = taal_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
+}
+
+static void taal_framedone_cb(int err, void *data)
+{
+ struct omap_dss_device *dssdev = data;
+ dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
+ dsi_bus_unlock();
+}
+
+static int taal_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h)
+{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bldev = td->bldev;
+ int r;
- bldev->props.power = FB_BLANK_UNBLANK;
- taal_bl_update_status(bldev);
+ dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
+
+ dsi_bus_lock();
+
+ if (!td->enabled) {
+ r = 0;
+ goto err;
+ }
+
+ r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
+ if (r)
+ goto err;
+
+ r = taal_set_update_window(x, y, w, h);
+ if (r)
+ goto err;
+
+ 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 */
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
-static void taal_setup_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
+static int taal_sync(struct omap_dss_device *dssdev)
{
- taal_set_update_window(x, y, w, h);
+ dev_dbg(&dssdev->dev, "sync\n");
+
+ dsi_bus_lock();
+ dsi_bus_unlock();
+
+ dev_dbg(&dssdev->dev, "sync done\n");
+
+ return 0;
}
-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;
@@ -744,25 +846,32 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
else
r = taal_dcs_write_0(DCS_TEAR_OFF);
+ omapdss_dsi_enable_te(dssdev, enable);
+
+ /* XXX for some reason, DSI TE breaks if we don't wait here.
+ * Panel bug? Needs more studying */
+ msleep(100);
+
return r;
}
-static int taal_wait_te(struct omap_dss_device *dssdev)
+static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- long wait = msecs_to_jiffies(500);
+ int r;
- if (!td->use_ext_te || !td->te_enabled)
- return 0;
+ dsi_bus_lock();
- 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;
- }
+ r = _taal_enable_te(dssdev, enable);
- return 0;
+ dsi_bus_unlock();
+
+ return r;
+}
+
+static int taal_get_te(struct omap_dss_device *dssdev)
+{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ return td->te_enabled;
}
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
@@ -772,16 +881,21 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
+ dsi_bus_lock();
+
if (td->enabled) {
r = taal_set_addr_mode(rotate, td->mirror);
-
if (r)
- return r;
+ goto err;
}
td->rotate = rotate;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static u8 taal_get_rotate(struct omap_dss_device *dssdev)
@@ -797,16 +911,20 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
+ dsi_bus_lock();
if (td->enabled) {
r = taal_set_addr_mode(td->rotate, enable);
-
if (r)
- return r;
+ goto err;
}
td->mirror = enable;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static bool taal_get_mirror(struct omap_dss_device *dssdev)
@@ -820,17 +938,23 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
u8 id1, id2, id3;
int r;
+ dsi_bus_lock();
+
r = taal_dcs_read_1(DCS_GET_ID1, &id1);
if (r)
- return r;
+ goto err;
r = taal_dcs_read_1(DCS_GET_ID2, &id2);
if (r)
- return r;
+ goto err;
r = taal_dcs_read_1(DCS_GET_ID3, &id3);
if (r)
- return r;
+ goto err;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static int taal_memory_read(struct omap_dss_device *dssdev,
@@ -841,6 +965,10 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
int first = 1;
int plen;
unsigned buf_used = 0;
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+ if (!td->enabled)
+ return -ENODEV;
if (size < w * h * 3)
return -ENOMEM;
@@ -849,6 +977,8 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
dssdev->panel.timings.x_res *
dssdev->panel.timings.y_res * 3);
+ dsi_bus_lock();
+
/* 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
* an error. */
@@ -857,11 +987,11 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
else
plen = 2;
- taal_setup_update(dssdev, x, y, w, h);
+ taal_set_update_window(x, y, w, h);
r = dsi_vc_set_max_rx_packet_size(TCH, plen);
if (r)
- return r;
+ goto err0;
while (buf_used < size) {
u8 dcs_cmd = first ? 0x2e : 0x3e;
@@ -894,7 +1024,8 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
err:
dsi_vc_set_max_rx_packet_size(TCH, 1);
-
+err0:
+ dsi_bus_unlock();
return r;
}
@@ -939,8 +1070,11 @@ 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)
- taal_enable_te(dssdev, true);
+ if (td->use_ext_te && td->te_enabled) {
+ r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+ if (r)
+ goto err;
+ }
dsi_bus_unlock();
@@ -958,6 +1092,20 @@ err:
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
}
+static int taal_set_update_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_update_mode mode)
+{
+ if (mode != OMAP_DSS_UPDATE_MANUAL)
+ return -EINVAL;
+ return 0;
+}
+
+static enum omap_dss_update_mode taal_get_update_mode(
+ struct omap_dss_device *dssdev)
+{
+ return OMAP_DSS_UPDATE_MANUAL;
+}
+
static struct omap_dss_driver taal_driver = {
.probe = taal_probe,
.remove = taal_remove,
@@ -967,9 +1115,18 @@ static struct omap_dss_driver taal_driver = {
.suspend = taal_suspend,
.resume = taal_resume,
- .setup_update = taal_setup_update,
+ .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,
- .wait_for_te = taal_wait_te,
+ .get_te = taal_get_te,
+
.set_rotate = taal_rotate,
.get_rotate = taal_get_rotate,
.set_mirror = taal_mirror,
@@ -977,6 +1134,8 @@ static struct omap_dss_driver taal_driver = {
.run_test = taal_run_test,
.memory_read = taal_memory_read,
+ .get_timings = taal_get_timings,
+
.driver = {
.name = "taal",
.owner = THIS_MODULE,
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
new file mode 100644
index 000000000000..fa434ca6e4b7
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
@@ -0,0 +1,154 @@
+/*
+ * LCD panel driver for Toppoly TDO35S
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on generic panel support
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/module.h>
+#include <linux/delay.h>
+
+#include <plat/display.h>
+
+static struct omap_video_timings toppoly_tdo_panel_timings = {
+ /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
+ .x_res = 480,
+ .y_res = 640,
+
+ .pixel_clock = 26000,
+
+ .hfp = 104,
+ .hsw = 8,
+ .hbp = 8,
+
+ .vfp = 4,
+ .vsw = 2,
+ .vbp = 2,
+};
+
+static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
+{
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS;
+ dssdev->panel.timings = toppoly_tdo_panel_timings;
+
+ return 0;
+}
+
+static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = toppoly_tdo_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
+{
+ toppoly_tdo_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
+{
+ toppoly_tdo_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = toppoly_tdo_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static struct omap_dss_driver generic_driver = {
+ .probe = toppoly_tdo_panel_probe,
+ .remove = toppoly_tdo_panel_remove,
+
+ .enable = toppoly_tdo_panel_enable,
+ .disable = toppoly_tdo_panel_disable,
+ .suspend = toppoly_tdo_panel_suspend,
+ .resume = toppoly_tdo_panel_resume,
+
+ .driver = {
+ .name = "toppoly_tdo35s_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init toppoly_tdo_panel_drv_init(void)
+{
+ return omap_dss_register_driver(&generic_driver);
+}
+
+static void __exit toppoly_tdo_panel_drv_exit(void)
+{
+ omap_dss_unregister_driver(&generic_driver);
+}
+
+module_init(toppoly_tdo_panel_drv_init);
+module_exit(toppoly_tdo_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 000000000000..d578feee3550
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,528 @@
+/*
+ * LCD panel driver for TPO TD043MTEA1
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+#define TPO_R02_MODE(x) ((x) & 7)
+#define TPO_R02_MODE_800x480 7
+#define TPO_R02_NCLK_RISING BIT(3)
+#define TPO_R02_HSYNC_HIGH BIT(4)
+#define TPO_R02_VSYNC_HIGH BIT(5)
+
+#define TPO_R03_NSTANDBY BIT(0)
+#define TPO_R03_EN_CP_CLK BIT(1)
+#define TPO_R03_EN_VGL_PUMP BIT(2)
+#define TPO_R03_EN_PWM BIT(3)
+#define TPO_R03_DRIVING_CAP_100 BIT(4)
+#define TPO_R03_EN_PRE_CHARGE BIT(6)
+#define TPO_R03_SOFTWARE_CTL BIT(7)
+
+#define TPO_R04_NFLIP_H BIT(0)
+#define TPO_R04_NFLIP_V BIT(1)
+#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
+#define TPO_R04_VGL_FREQ_1H BIT(4)
+
+#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
+ TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
+ TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
+ TPO_R03_SOFTWARE_CTL)
+
+#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
+ TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
+
+static const u16 tpo_td043_def_gamma[12] = {
+ 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
+};
+
+struct tpo_td043_device {
+ struct spi_device *spi;
+ struct regulator *vcc_reg;
+ u16 gamma[12];
+ u32 mode;
+ u32 hmirror:1;
+ u32 vmirror:1;
+};
+
+static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
+{
+ struct spi_message m;
+ struct spi_transfer xfer;
+ u16 w;
+ int r;
+
+ spi_message_init(&m);
+
+ memset(&xfer, 0, sizeof(xfer));
+
+ w = ((u16)addr << 10) | (1 << 8) | data;
+ xfer.tx_buf = &w;
+ xfer.bits_per_word = 16;
+ xfer.len = 2;
+ spi_message_add_tail(&xfer, &m);
+
+ r = spi_sync(spi, &m);
+ if (r < 0)
+ dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
+ return r;
+}
+
+static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
+{
+ u8 i, val;
+
+ /* gamma bits [9:8] */
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x11, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x12, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x13, val);
+
+ /* gamma bits [7:0] */
+ for (val = i = 0; i < 12; i++)
+ tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
+}
+
+static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
+{
+ u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \
+ TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
+ if (h)
+ reg4 &= ~TPO_R04_NFLIP_H;
+ if (v)
+ reg4 &= ~TPO_R04_NFLIP_V;
+
+ return tpo_td043_write(spi, 4, reg4);
+}
+
+static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+ tpo_td043->hmirror = enable;
+ return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+ tpo_td043->vmirror);
+}
+
+static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+ return tpo_td043->hmirror;
+}
+
+static ssize_t tpo_td043_vmirror_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror);
+}
+
+static ssize_t tpo_td043_vmirror_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ ret = strict_strtol(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
+ if (ret < 0)
+ return ret;
+
+ tpo_td043->vmirror = val;
+
+ return count;
+}
+
+static ssize_t tpo_td043_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode);
+}
+
+static ssize_t tpo_td043_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ ret = strict_strtol(buf, 0, &val);
+ if (ret != 0 || val & ~7)
+ return -EINVAL;
+
+ tpo_td043->mode = val;
+
+ val |= TPO_R02_NCLK_RISING;
+ tpo_td043_write(tpo_td043->spi, 2, val);
+
+ return count;
+}
+
+static ssize_t tpo_td043_gamma_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) {
+ ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
+ tpo_td043->gamma[i]);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t tpo_td043_gamma_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ unsigned int g[12];
+ int ret;
+ int i;
+
+ ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
+ &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
+ &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+
+ if (ret != 12)
+ return -EINVAL;
+
+ for (i = 0; i < 12; i++)
+ tpo_td043->gamma[i] = g[i];
+
+ tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+ return count;
+}
+
+static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
+ tpo_td043_vmirror_show, tpo_td043_vmirror_store);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ tpo_td043_mode_show, tpo_td043_mode_store);
+static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
+ tpo_td043_gamma_show, tpo_td043_gamma_store);
+
+static struct attribute *tpo_td043_attrs[] = {
+ &dev_attr_vmirror.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_gamma.attr,
+ NULL,
+};
+
+static struct attribute_group tpo_td043_attr_group = {
+ .attrs = tpo_td043_attrs,
+};
+
+static const struct omap_video_timings tpo_td043_timings = {
+ .x_res = 800,
+ .y_res = 480,
+
+ .pixel_clock = 36000,
+
+ .hsw = 1,
+ .hfp = 68,
+ .hbp = 214,
+
+ .vsw = 1,
+ .vfp = 39,
+ .vbp = 34,
+};
+
+static int tpo_td043_power_on(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ regulator_enable(tpo_td043->vcc_reg);
+
+ /* wait for power up */
+ msleep(160);
+
+ if (gpio_is_valid(nreset_gpio))
+ gpio_set_value(nreset_gpio, 1);
+
+ tpo_td043_write(tpo_td043->spi, 2,
+ TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
+ tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL);
+ tpo_td043_write(tpo_td043->spi, 0x20, 0xf0);
+ tpo_td043_write(tpo_td043->spi, 0x21, 0xf0);
+ tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+ tpo_td043->vmirror);
+ tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void tpo_td043_power_off(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+
+ tpo_td043_write(tpo_td043->spi, 3,
+ TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
+
+ if (gpio_is_valid(nreset_gpio))
+ gpio_set_value(nreset_gpio, 0);
+
+ /* wait for at least 2 vsyncs before cutting off power */
+ msleep(50);
+
+ tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY);
+
+ regulator_disable(tpo_td043->vcc_reg);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int tpo_td043_enable(struct omap_dss_device *dssdev)
+{
+ int ret;
+
+ dev_dbg(&dssdev->dev, "enable\n");
+
+ ret = tpo_td043_power_on(dssdev);
+ if (ret)
+ return ret;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void tpo_td043_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "disable\n");
+
+ tpo_td043_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int tpo_td043_suspend(struct omap_dss_device *dssdev)
+{
+ tpo_td043_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int tpo_td043_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = tpo_td043_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static int tpo_td043_probe(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+ int ret = 0;
+
+ dev_dbg(&dssdev->dev, "probe\n");
+
+ if (tpo_td043 == NULL) {
+ dev_err(&dssdev->dev, "missing tpo_td043_device\n");
+ return -ENODEV;
+ }
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS |
+ OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;
+ dssdev->panel.timings = tpo_td043_timings;
+ dssdev->ctrl.pixel_size = 24;
+
+ tpo_td043->mode = TPO_R02_MODE_800x480;
+ memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
+
+ tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
+ if (IS_ERR(tpo_td043->vcc_reg)) {
+ dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
+ ret = PTR_ERR(tpo_td043->vcc_reg);
+ goto fail_regulator;
+ }
+
+ if (gpio_is_valid(nreset_gpio)) {
+ ret = gpio_request(nreset_gpio, "lcd reset");
+ if (ret < 0) {
+ dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
+ goto fail_gpio_req;
+ }
+
+ ret = gpio_direction_output(nreset_gpio, 0);
+ if (ret < 0) {
+ dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
+ goto fail_gpio_direction;
+ }
+ }
+
+ ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+ if (ret)
+ dev_warn(&dssdev->dev, "failed to create sysfs files\n");
+
+ return 0;
+
+fail_gpio_direction:
+ gpio_free(nreset_gpio);
+fail_gpio_req:
+ regulator_put(tpo_td043->vcc_reg);
+fail_regulator:
+ kfree(tpo_td043);
+ return ret;
+}
+
+static void tpo_td043_remove(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+
+ dev_dbg(&dssdev->dev, "remove\n");
+
+ sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+ regulator_put(tpo_td043->vcc_reg);
+ if (gpio_is_valid(nreset_gpio))
+ gpio_free(nreset_gpio);
+}
+
+static struct omap_dss_driver tpo_td043_driver = {
+ .probe = tpo_td043_probe,
+ .remove = tpo_td043_remove,
+
+ .enable = tpo_td043_enable,
+ .disable = tpo_td043_disable,
+ .suspend = tpo_td043_suspend,
+ .resume = tpo_td043_resume,
+ .set_mirror = tpo_td043_set_hmirror,
+ .get_mirror = tpo_td043_get_hmirror,
+
+ .driver = {
+ .name = "tpo_td043mtea1_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int tpo_td043_spi_probe(struct spi_device *spi)
+{
+ struct omap_dss_device *dssdev = spi->dev.platform_data;
+ struct tpo_td043_device *tpo_td043;
+ int ret;
+
+ if (dssdev == NULL) {
+ dev_err(&spi->dev, "missing dssdev\n");
+ return -ENODEV;
+ }
+
+ spi->bits_per_word = 16;
+ spi->mode = SPI_MODE_0;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
+ return ret;
+ }
+
+ tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL);
+ if (tpo_td043 == NULL)
+ return -ENOMEM;
+
+ tpo_td043->spi = spi;
+ dev_set_drvdata(&spi->dev, tpo_td043);
+ dev_set_drvdata(&dssdev->dev, tpo_td043);
+
+ omap_dss_register_driver(&tpo_td043_driver);
+
+ return 0;
+}
+
+static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
+
+ omap_dss_unregister_driver(&tpo_td043_driver);
+ kfree(tpo_td043);
+
+ return 0;
+}
+
+static struct spi_driver tpo_td043_spi_driver = {
+ .driver = {
+ .name = "tpo_td043mtea1_panel_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = tpo_td043_spi_probe,
+ .remove = __devexit_p(tpo_td043_spi_remove),
+};
+
+static int __init tpo_td043_init(void)
+{
+ return spi_register_driver(&tpo_td043_spi_driver);
+}
+
+static void __exit tpo_td043_exit(void)
+{
+ spi_unregister_driver(&tpo_td043_spi_driver);
+}
+
+module_init(tpo_td043_init);
+module_exit(tpo_td043_exit);
+
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index c63ce767b277..87afb81b2c44 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -30,19 +30,29 @@ config OMAP2_DSS_COLLECT_IRQ_STATS
depends on OMAP2_DSS_DEBUG_SUPPORT
default n
help
- Collect DSS IRQ statistics, printable via debugfs
+ Collect DSS IRQ statistics, printable via debugfs.
+
+ The statistics can be found from
+ <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
+ <debugfs>/omapdss/dsi_irq for DSI interrupts.
config OMAP2_DSS_RFBI
bool "RFBI support"
default n
help
- MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
+ MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
+ Instrument's terminology).
+
+ DBI is a bus between the host processor and a peripheral,
+ such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DBI spesifications.
config OMAP2_DSS_VENC
bool "VENC support"
default y
help
- OMAP Video Encoder support.
+ OMAP Video Encoder support for S-Video and composite TV-out.
config OMAP2_DSS_SDI
bool "SDI support"
@@ -51,12 +61,20 @@ config OMAP2_DSS_SDI
help
SDI (Serial Display Interface) support.
+ SDI is a high speed one-way display serial bus between the host
+ processor and a display.
+
config OMAP2_DSS_DSI
bool "DSI support"
depends on ARCH_OMAP3
default n
help
- MIPI DSI support.
+ MIPI DSI (Display Serial Interface) support.
+
+ DSI is a high speed half-duplex serial interface between the host
+ processor and a peripheral, such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DSI spesifications.
config OMAP2_DSS_USE_DSI_PLL
bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 82918eec6d2e..7ebe50b335ed 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -31,6 +31,7 @@
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/device.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
#include <plat/clock.h>
@@ -47,6 +48,10 @@ static struct {
struct clk *dss_54m_fck;
struct clk *dss_96m_fck;
unsigned num_clks_enabled;
+
+ struct regulator *vdds_dsi_reg;
+ struct regulator *vdds_sdi_reg;
+ struct regulator *vdda_dac_reg;
} core;
static void dss_clk_enable_all_no_ctx(void);
@@ -284,9 +289,11 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks)
void dss_clk_enable(enum dss_clock clks)
{
+ bool check_ctx = core.num_clks_enabled == 0;
+
dss_clk_enable_no_ctx(clks);
- if (cpu_is_omap34xx() && dss_need_ctx_restore())
+ if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
restore_all_ctx();
}
@@ -352,6 +359,50 @@ static void dss_clk_disable_all(void)
dss_clk_disable(clks);
}
+/* REGULATORS */
+
+struct regulator *dss_get_vdds_dsi(void)
+{
+ struct regulator *reg;
+
+ if (core.vdds_dsi_reg != NULL)
+ return core.vdds_dsi_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdds_dsi");
+ if (!IS_ERR(reg))
+ core.vdds_dsi_reg = reg;
+
+ return reg;
+}
+
+struct regulator *dss_get_vdds_sdi(void)
+{
+ struct regulator *reg;
+
+ if (core.vdds_sdi_reg != NULL)
+ return core.vdds_sdi_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdds_sdi");
+ if (!IS_ERR(reg))
+ core.vdds_sdi_reg = reg;
+
+ return reg;
+}
+
+struct regulator *dss_get_vdda_dac(void)
+{
+ struct regulator *reg;
+
+ if (core.vdda_dac_reg != NULL)
+ return core.vdda_dac_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdda_dac");
+ if (!IS_ERR(reg))
+ core.vdda_dac_reg = reg;
+
+ return reg;
+}
+
/* DEBUGFS */
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
static void dss_debug_dump_clocks(struct seq_file *s)
@@ -397,10 +448,12 @@ static int dss_initialize_debugfs(void)
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
&dss_debug_dump_clocks, &dss_debug_fops);
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir,
&dispc_dump_irqs, &dss_debug_fops);
+#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
+#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
&dsi_dump_irqs, &dss_debug_fops);
#endif
@@ -473,7 +526,7 @@ static int omap_dss_probe(struct platform_device *pdev)
}
#endif
- r = dpi_init();
+ r = dpi_init(pdev);
if (r) {
DSSERR("Failed to initialize dpi\n");
goto fail0;
@@ -718,16 +771,14 @@ static int dss_driver_probe(struct device *dev)
dss_init_device(core.pdev, dssdev);
- /* skip this if the device is behind a ctrl */
- if (!dssdev->panel.ctrl) {
- force = pdata->default_device == dssdev;
- dss_recheck_connections(dssdev, force);
- }
+ force = pdata->default_device == dssdev;
+ dss_recheck_connections(dssdev, force);
r = dssdrv->probe(dssdev);
if (r) {
DSSERR("driver probe failed: %d\n", r);
+ dss_uninit_device(core.pdev, dssdev);
return r;
}
@@ -760,6 +811,13 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
dssdriver->driver.bus = &dss_bus_type;
dssdriver->driver.probe = dss_driver_probe;
dssdriver->driver.remove = dss_driver_remove;
+
+ if (dssdriver->get_resolution == NULL)
+ dssdriver->get_resolution = omapdss_default_get_resolution;
+ if (dssdriver->get_recommended_bpp == NULL)
+ dssdriver->get_recommended_bpp =
+ omapdss_default_get_recommended_bpp;
+
return driver_register(&dssdriver->driver);
}
EXPORT_SYMBOL(omap_dss_register_driver);
@@ -808,8 +866,6 @@ static void omap_dss_dev_release(struct device *dev)
int omap_dss_register_device(struct omap_dss_device *dssdev)
{
static int dev_num;
- static int panel_num;
- int r;
WARN_ON(!dssdev->driver_name);
@@ -818,36 +874,12 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
dssdev->dev.parent = &dss_bus;
dssdev->dev.release = omap_dss_dev_release;
dev_set_name(&dssdev->dev, "display%d", dev_num++);
- r = device_register(&dssdev->dev);
- if (r)
- return r;
-
- if (dssdev->ctrl.panel) {
- struct omap_dss_device *panel = dssdev->ctrl.panel;
-
- panel->panel.ctrl = dssdev;
-
- reset_device(&panel->dev, 1);
- panel->dev.bus = &dss_bus_type;
- panel->dev.parent = &dssdev->dev;
- panel->dev.release = omap_dss_dev_release;
- dev_set_name(&panel->dev, "panel%d", panel_num++);
- r = device_register(&panel->dev);
- if (r)
- return r;
- }
-
- return 0;
+ return device_register(&dssdev->dev);
}
void omap_dss_unregister_device(struct omap_dss_device *dssdev)
{
device_unregister(&dssdev->dev);
-
- if (dssdev->ctrl.panel) {
- struct omap_dss_device *panel = dssdev->ctrl.panel;
- device_unregister(&panel->dev);
- }
}
/* BUS */
@@ -901,6 +933,21 @@ static int __init omap_dss_init(void)
static void __exit omap_dss_exit(void)
{
+ if (core.vdds_dsi_reg != NULL) {
+ regulator_put(core.vdds_dsi_reg);
+ core.vdds_dsi_reg = NULL;
+ }
+
+ if (core.vdds_sdi_reg != NULL) {
+ regulator_put(core.vdds_sdi_reg);
+ core.vdds_sdi_reg = NULL;
+ }
+
+ if (core.vdda_dac_reg != NULL) {
+ regulator_put(core.vdda_dac_reg);
+ core.vdda_dac_reg = NULL;
+ }
+
platform_driver_unregister(&omap_dss_driver);
omap_dss_bus_unregister();
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index de8bfbac9e26..e777e352dbcd 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1725,7 +1725,7 @@ static void _enable_lcd_out(bool enable)
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
}
-void dispc_enable_lcd_out(bool enable)
+static void dispc_enable_lcd_out(bool enable)
{
struct completion frame_done_completion;
bool is_on;
@@ -1772,7 +1772,7 @@ static void _enable_digit_out(bool enable)
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
}
-void dispc_enable_digit_out(bool enable)
+static void dispc_enable_digit_out(bool enable)
{
struct completion frame_done_completion;
int r;
@@ -1836,6 +1836,26 @@ void dispc_enable_digit_out(bool enable)
enable_clocks(0);
}
+bool dispc_is_channel_enabled(enum omap_channel channel)
+{
+ if (channel == OMAP_DSS_CHANNEL_LCD)
+ return !!REG_GET(DISPC_CONTROL, 0, 0);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ return !!REG_GET(DISPC_CONTROL, 1, 1);
+ else
+ BUG();
+}
+
+void dispc_enable_channel(enum omap_channel channel, bool enable)
+{
+ if (channel == OMAP_DSS_CHANNEL_LCD)
+ dispc_enable_lcd_out(enable);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ dispc_enable_digit_out(enable);
+ else
+ BUG();
+}
+
void dispc_lcd_enable_signal_polarity(bool act_high)
{
enable_clocks(1);
@@ -2198,7 +2218,7 @@ unsigned long dispc_fclk_rate(void)
{
unsigned long r = 0;
- if (dss_get_dispc_clk_source() == 0)
+ if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
r = dss_clk_get_rate(DSS_CLK_FCK1);
else
#ifdef CONFIG_OMAP2_DSS_DSI
@@ -2251,7 +2271,7 @@ void dispc_dump_clocks(struct seq_file *s)
seq_printf(s, "- DISPC -\n");
seq_printf(s, "dispc fclk source = %s\n",
- dss_get_dispc_clk_source() == 0 ?
+ dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
"dss1_alwon_fclk" : "dsi1_pll_fclk");
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
@@ -2301,8 +2321,6 @@ void dispc_dump_irqs(struct seq_file *s)
PIS(WAKEUP);
#undef PIS
}
-#else
-void dispc_dump_irqs(struct seq_file *s) { }
#endif
void dispc_dump_regs(struct seq_file *s)
@@ -2854,12 +2872,13 @@ static void dispc_error_worker(struct work_struct *work)
manager = mgr;
enable = mgr->device->state ==
OMAP_DSS_DISPLAY_ACTIVE;
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
break;
}
}
if (manager) {
+ struct omap_dss_device *dssdev = manager->device;
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
@@ -2874,7 +2893,7 @@ static void dispc_error_worker(struct work_struct *work)
dispc_go(manager->id);
mdelay(50);
if (enable)
- manager->device->enable(manager->device);
+ dssdev->driver->enable(dssdev);
}
}
@@ -2892,12 +2911,13 @@ static void dispc_error_worker(struct work_struct *work)
manager = mgr;
enable = mgr->device->state ==
OMAP_DSS_DISPLAY_ACTIVE;
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
break;
}
}
if (manager) {
+ struct omap_dss_device *dssdev = manager->device;
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
@@ -2912,7 +2932,7 @@ static void dispc_error_worker(struct work_struct *work)
dispc_go(manager->id);
mdelay(50);
if (enable)
- manager->device->enable(manager->device);
+ dssdev->driver->enable(dssdev);
}
}
@@ -2923,7 +2943,7 @@ static void dispc_error_worker(struct work_struct *work)
mgr = omap_dss_get_overlay_manager(i);
if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
}
}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 3b92b84b9560..6a74ea116d29 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -53,11 +53,11 @@ static ssize_t display_enabled_store(struct device *dev,
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
if (enabled) {
- r = dssdev->enable(dssdev);
+ r = dssdev->driver->enable(dssdev);
if (r)
return r;
} else {
- dssdev->disable(dssdev);
+ dssdev->driver->disable(dssdev);
}
}
@@ -69,8 +69,8 @@ static ssize_t display_upd_mode_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
- if (dssdev->get_update_mode)
- mode = dssdev->get_update_mode(dssdev);
+ if (dssdev->driver->get_update_mode)
+ mode = dssdev->driver->get_update_mode(dssdev);
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
}
@@ -94,7 +94,7 @@ static ssize_t display_upd_mode_store(struct device *dev,
return -EINVAL;
}
- r = dssdev->set_update_mode(dssdev, mode);
+ r = dssdev->driver->set_update_mode(dssdev, mode);
if (r)
return r;
@@ -106,7 +106,8 @@ static ssize_t display_tear_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
return snprintf(buf, PAGE_SIZE, "%d\n",
- dssdev->get_te ? dssdev->get_te(dssdev) : 0);
+ dssdev->driver->get_te ?
+ dssdev->driver->get_te(dssdev) : 0);
}
static ssize_t display_tear_store(struct device *dev,
@@ -116,12 +117,12 @@ static ssize_t display_tear_store(struct device *dev,
unsigned long te;
int r;
- if (!dssdev->enable_te || !dssdev->get_te)
+ if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
return -ENOENT;
te = simple_strtoul(buf, NULL, 0);
- r = dssdev->enable_te(dssdev, te);
+ r = dssdev->driver->enable_te(dssdev, te);
if (r)
return r;
@@ -134,10 +135,10 @@ static ssize_t display_timings_show(struct device *dev,
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t;
- if (!dssdev->get_timings)
+ if (!dssdev->driver->get_timings)
return -ENOENT;
- dssdev->get_timings(dssdev, &t);
+ dssdev->driver->get_timings(dssdev, &t);
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
t.pixel_clock,
@@ -152,7 +153,7 @@ static ssize_t display_timings_store(struct device *dev,
struct omap_video_timings t;
int r, found;
- if (!dssdev->set_timings || !dssdev->check_timings)
+ if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
return -ENOENT;
found = 0;
@@ -171,11 +172,11 @@ static ssize_t display_timings_store(struct device *dev,
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
return -EINVAL;
- r = dssdev->check_timings(dssdev, &t);
+ r = dssdev->driver->check_timings(dssdev, &t);
if (r)
return r;
- dssdev->set_timings(dssdev, &t);
+ dssdev->driver->set_timings(dssdev, &t);
return size;
}
@@ -185,9 +186,9 @@ static ssize_t display_rotate_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rotate;
- if (!dssdev->get_rotate)
+ if (!dssdev->driver->get_rotate)
return -ENOENT;
- rotate = dssdev->get_rotate(dssdev);
+ rotate = dssdev->driver->get_rotate(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
}
@@ -198,12 +199,12 @@ static ssize_t display_rotate_store(struct device *dev,
unsigned long rot;
int r;
- if (!dssdev->set_rotate || !dssdev->get_rotate)
+ if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
return -ENOENT;
rot = simple_strtoul(buf, NULL, 0);
- r = dssdev->set_rotate(dssdev, rot);
+ r = dssdev->driver->set_rotate(dssdev, rot);
if (r)
return r;
@@ -215,9 +216,9 @@ static ssize_t display_mirror_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int mirror;
- if (!dssdev->get_mirror)
+ if (!dssdev->driver->get_mirror)
return -ENOENT;
- mirror = dssdev->get_mirror(dssdev);
+ mirror = dssdev->driver->get_mirror(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
}
@@ -228,12 +229,12 @@ static ssize_t display_mirror_store(struct device *dev,
unsigned long mirror;
int r;
- if (!dssdev->set_mirror || !dssdev->get_mirror)
+ if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
return -ENOENT;
mirror = simple_strtoul(buf, NULL, 0);
- r = dssdev->set_mirror(dssdev, mirror);
+ r = dssdev->driver->set_mirror(dssdev, mirror);
if (r)
return r;
@@ -246,10 +247,10 @@ static ssize_t display_wss_show(struct device *dev,
struct omap_dss_device *dssdev = to_dss_device(dev);
unsigned int wss;
- if (!dssdev->get_wss)
+ if (!dssdev->driver->get_wss)
return -ENOENT;
- wss = dssdev->get_wss(dssdev);
+ wss = dssdev->driver->get_wss(dssdev);
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
}
@@ -261,7 +262,7 @@ static ssize_t display_wss_store(struct device *dev,
unsigned long wss;
int r;
- if (!dssdev->get_wss || !dssdev->set_wss)
+ if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
return -ENOENT;
if (strict_strtoul(buf, 0, &wss))
@@ -270,7 +271,7 @@ static ssize_t display_wss_store(struct device *dev,
if (wss > 0xfffff)
return -EINVAL;
- r = dssdev->set_wss(dssdev, wss);
+ r = dssdev->driver->set_wss(dssdev, wss);
if (r)
return r;
@@ -303,12 +304,13 @@ static struct device_attribute *display_sysfs_attrs[] = {
NULL
};
-static void default_get_resolution(struct omap_dss_device *dssdev,
+void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
*xres = dssdev->panel.timings.x_res;
*yres = dssdev->panel.timings.y_res;
}
+EXPORT_SYMBOL(omapdss_default_get_resolution);
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
@@ -323,24 +325,8 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
*fifo_low = fifo_size - burst_size_bytes;
}
-static int default_wait_vsync(struct omap_dss_device *dssdev)
+int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
{
- unsigned long timeout = msecs_to_jiffies(500);
- u32 irq;
-
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
- irq = DISPC_IRQ_EVSYNC_ODD;
- else
- irq = DISPC_IRQ_VSYNC;
-
- return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
-}
-
-static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
-{
- if (dssdev->panel.recommended_bpp)
- return dssdev->panel.recommended_bpp;
-
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
if (dssdev->phy.dpi.data_lines == 24)
@@ -362,6 +348,7 @@ static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
BUG();
}
}
+EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
/* Checks if replication logic should be used. Only use for active matrix,
* when overlay is in RGB12U or RGB16 mode, and LCD interface is
@@ -425,10 +412,6 @@ void dss_init_device(struct platform_device *pdev,
return;
}
- dssdev->get_resolution = default_get_resolution;
- dssdev->get_recommended_bpp = default_get_recommended_bpp;
- dssdev->wait_vsync = default_wait_vsync;
-
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
@@ -502,13 +485,13 @@ static int dss_suspend_device(struct device *dev, void *data)
return 0;
}
- if (!dssdev->suspend) {
+ if (!dssdev->driver->suspend) {
DSSERR("display '%s' doesn't implement suspend\n",
dssdev->name);
return -ENOSYS;
}
- r = dssdev->suspend(dssdev);
+ r = dssdev->driver->suspend(dssdev);
if (r)
return r;
@@ -537,8 +520,8 @@ static int dss_resume_device(struct device *dev, void *data)
int r;
struct omap_dss_device *dssdev = to_dss_device(dev);
- if (dssdev->activate_after_resume && dssdev->resume) {
- r = dssdev->resume(dssdev);
+ if (dssdev->activate_after_resume && dssdev->driver->resume) {
+ r = dssdev->driver->resume(dssdev);
if (r)
return r;
}
@@ -558,7 +541,7 @@ 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->disable(dssdev);
+ dssdev->driver->disable(dssdev);
return 0;
}
@@ -591,10 +574,6 @@ struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
int match(struct device *dev, void *data)
{
- /* skip panels connected to controllers */
- if (to_dss_device(dev)->panel.ctrl)
- return 0;
-
return 1;
}
@@ -626,45 +605,21 @@ EXPORT_SYMBOL(omap_dss_find_device);
int omap_dss_start_device(struct omap_dss_device *dssdev)
{
- int r;
-
if (!dssdev->driver) {
DSSDBG("no driver\n");
- r = -ENODEV;
- goto err0;
- }
-
- if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
- DSSDBG("no panel driver\n");
- r = -ENODEV;
- goto err0;
+ return -ENODEV;
}
if (!try_module_get(dssdev->dev.driver->owner)) {
- r = -ENODEV;
- goto err0;
- }
-
- if (dssdev->ctrl.panel) {
- if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
- r = -ENODEV;
- goto err1;
- }
+ return -ENODEV;
}
return 0;
-err1:
- module_put(dssdev->dev.driver->owner);
-err0:
- return r;
}
EXPORT_SYMBOL(omap_dss_start_device);
void omap_dss_stop_device(struct omap_dss_device *dssdev)
{
- if (dssdev->ctrl.panel)
- module_put(dssdev->ctrl.panel->dev.driver->owner);
-
module_put(dssdev->dev.driver->owner);
}
EXPORT_SYMBOL(omap_dss_stop_device);
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 2d71031baa25..960e977a8bf0 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -25,7 +25,10 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
#include <plat/cpu.h>
@@ -33,7 +36,7 @@
#include "dss.h"
static struct {
- int update_enabled;
+ struct regulator *vdds_dsi_reg;
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
@@ -53,7 +56,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
if (r)
return r;
- dss_select_clk_source(0, 1);
+ dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
r = dispc_set_clock_div(&dispc_cinfo);
if (r)
@@ -150,7 +153,7 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
return 0;
}
-static int dpi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
int r;
@@ -160,10 +163,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("display already enabled\n");
- r = -EINVAL;
- goto err1;
+ if (cpu_is_omap34xx()) {
+ r = regulator_enable(dpi.vdds_dsi_reg);
+ if (r)
+ goto err1;
}
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -184,18 +187,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
- dispc_enable_lcd_out(1);
-
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err5;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ dssdev->manager->enable(dssdev->manager);
return 0;
-err5:
- dispc_enable_lcd_out(0);
err4:
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dsi_pll_uninit();
@@ -204,78 +199,35 @@ err3:
#endif
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ if (cpu_is_omap34xx())
+ regulator_disable(dpi.vdds_dsi_reg);
err1:
omap_dss_stop_device(dssdev);
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_dpi_display_enable);
-static int dpi_display_resume(struct omap_dss_device *dssdev);
-
-static void dpi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- return;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- dpi_display_resume(dssdev);
-
- dssdev->driver->disable(dssdev);
-
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- dss_select_clk_source(0, 0);
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
dsi_pll_uninit();
dss_clk_disable(DSS_CLK_FCK2);
#endif
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ if (cpu_is_omap34xx())
+ regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
}
+EXPORT_SYMBOL(omapdss_dpi_display_disable);
-static int dpi_display_suspend(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
-
- DSSDBG("dpi_display_suspend\n");
-
- if (dssdev->driver->suspend)
- dssdev->driver->suspend(dssdev);
-
- dispc_enable_lcd_out(0);
-
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
- return 0;
-}
-
-static int dpi_display_resume(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
-
- DSSDBG("dpi_display_resume\n");
-
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dispc_enable_lcd_out(1);
-
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void dpi_set_timings(struct omap_dss_device *dssdev,
+void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
DSSDBG("dpi_set_timings\n");
@@ -285,8 +237,9 @@ static void dpi_set_timings(struct omap_dss_device *dssdev,
dispc_go(OMAP_DSS_CHANNEL_LCD);
}
}
+EXPORT_SYMBOL(dpi_set_timings);
-static int dpi_check_timings(struct omap_dss_device *dssdev,
+int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
bool is_tft;
@@ -340,56 +293,25 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
return 0;
}
-
-static void dpi_get_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- *timings = dssdev->panel.timings;
-}
-
-static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- if (mode == OMAP_DSS_UPDATE_MANUAL)
- return -EINVAL;
-
- if (mode == OMAP_DSS_UPDATE_DISABLED) {
- dispc_enable_lcd_out(0);
- dpi.update_enabled = 0;
- } else {
- dispc_enable_lcd_out(1);
- dpi.update_enabled = 1;
- }
-
- return 0;
-}
-
-static enum omap_dss_update_mode dpi_display_get_update_mode(
- struct omap_dss_device *dssdev)
-{
- return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
- OMAP_DSS_UPDATE_DISABLED;
-}
+EXPORT_SYMBOL(dpi_check_timings);
int dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- dssdev->enable = dpi_display_enable;
- dssdev->disable = dpi_display_disable;
- dssdev->suspend = dpi_display_suspend;
- dssdev->resume = dpi_display_resume;
- dssdev->set_timings = dpi_set_timings;
- dssdev->check_timings = dpi_check_timings;
- dssdev->get_timings = dpi_get_timings;
- dssdev->set_update_mode = dpi_display_set_update_mode;
- dssdev->get_update_mode = dpi_display_get_update_mode;
-
return 0;
}
-int dpi_init(void)
+int dpi_init(struct platform_device *pdev)
{
+ if (cpu_is_omap34xx()) {
+ dpi.vdds_dsi_reg = dss_get_vdds_dsi();
+ if (IS_ERR(dpi.vdds_dsi_reg)) {
+ DSSERR("can't get VDDS_DSI regulator\n");
+ return PTR_ERR(dpi.vdds_dsi_reg);
+ }
+ }
+
return 0;
}
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 6122178f5f85..3af207b2bde3 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -27,11 +27,12 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/semaphore.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/kthread.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#include <plat/display.h>
#include <plat/clock.h>
@@ -199,7 +200,6 @@ enum dsi_vc_mode {
};
struct dsi_update_region {
- bool dirty;
u16 x, y, w, h;
struct omap_dss_device *device;
};
@@ -224,29 +224,25 @@ static struct
enum dsi_vc_mode mode;
struct omap_dss_device *dssdev;
enum fifo_size fifo_size;
- int dest_per; /* destination peripheral 0-3 */
} vc[4];
struct mutex lock;
- struct mutex bus_lock;
+ struct semaphore bus_lock;
unsigned pll_locked;
struct completion bta_completion;
- struct task_struct *thread;
- wait_queue_head_t waitqueue;
-
- spinlock_t update_lock;
- bool framedone_received;
+ int update_channel;
struct dsi_update_region update_region;
- struct dsi_update_region active_update_region;
- struct completion update_completion;
- enum omap_dss_update_mode user_update_mode;
- enum omap_dss_update_mode update_mode;
bool te_enabled;
- bool use_ext_te;
+
+ struct work_struct framedone_work;
+ void (*framedone_callback)(int, void *);
+ void *framedone_data;
+
+ struct delayed_work framedone_timeout_work;
#ifdef DSI_CATCH_MISSING_TE
struct timer_list te_timer;
@@ -261,8 +257,6 @@ static struct
#ifdef DEBUG
ktime_t perf_setup_time;
ktime_t perf_start_time;
- ktime_t perf_start_time_auto;
- int perf_measure_frames;
#endif
int debug_read;
int debug_write;
@@ -299,16 +293,21 @@ void dsi_restore_context(void)
void dsi_bus_lock(void)
{
- mutex_lock(&dsi.bus_lock);
+ down(&dsi.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_lock);
void dsi_bus_unlock(void)
{
- mutex_unlock(&dsi.bus_lock);
+ up(&dsi.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_unlock);
+static bool dsi_bus_is_locked(void)
+{
+ return dsi.bus_lock.count == 0;
+}
+
static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
int value)
{
@@ -333,12 +332,6 @@ static void dsi_perf_mark_start(void)
dsi.perf_start_time = ktime_get();
}
-static void dsi_perf_mark_start_auto(void)
-{
- dsi.perf_measure_frames = 0;
- dsi.perf_start_time_auto = ktime_get();
-}
-
static void dsi_perf_show(const char *name)
{
ktime_t t, setup_time, trans_time;
@@ -348,9 +341,6 @@ static void dsi_perf_show(const char *name)
if (!dsi_perf)
return;
- if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
- return;
-
t = ktime_get();
setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
@@ -365,76 +355,23 @@ static void dsi_perf_show(const char *name)
total_us = setup_us + trans_us;
- total_bytes = dsi.active_update_region.w *
- dsi.active_update_region.h *
- dsi.active_update_region.device->ctrl.pixel_size / 8;
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
- static u32 s_total_trans_us, s_total_setup_us;
- static u32 s_min_trans_us = 0xffffffff, s_min_setup_us;
- static u32 s_max_trans_us, s_max_setup_us;
- const int numframes = 100;
- ktime_t total_time_auto;
- u32 total_time_auto_us;
-
- dsi.perf_measure_frames++;
-
- if (setup_us < s_min_setup_us)
- s_min_setup_us = setup_us;
+ total_bytes = dsi.update_region.w *
+ dsi.update_region.h *
+ dsi.update_region.device->ctrl.pixel_size / 8;
- if (setup_us > s_max_setup_us)
- s_max_setup_us = setup_us;
-
- s_total_setup_us += setup_us;
-
- if (trans_us < s_min_trans_us)
- s_min_trans_us = trans_us;
-
- if (trans_us > s_max_trans_us)
- s_max_trans_us = trans_us;
-
- s_total_trans_us += trans_us;
-
- if (dsi.perf_measure_frames < numframes)
- return;
-
- total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
- total_time_auto_us = (u32)ktime_to_us(total_time_auto);
-
- printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
- "trans %u/%u/%u\n",
- name,
- 1000 * 1000 * numframes / total_time_auto_us,
- s_min_setup_us,
- s_max_setup_us,
- s_total_setup_us / numframes,
- s_min_trans_us,
- s_max_trans_us,
- s_total_trans_us / numframes);
-
- s_total_setup_us = 0;
- s_min_setup_us = 0xffffffff;
- s_max_setup_us = 0;
- s_total_trans_us = 0;
- s_min_trans_us = 0xffffffff;
- s_max_trans_us = 0;
- dsi_perf_mark_start_auto();
- } else {
- printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
- "%u bytes, %u kbytes/sec\n",
- name,
- setup_us,
- trans_us,
- total_us,
- 1000*1000 / total_us,
- total_bytes,
- total_bytes * 1000 / total_us);
- }
+ printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
+ "%u bytes, %u kbytes/sec\n",
+ name,
+ setup_us,
+ trans_us,
+ total_us,
+ 1000*1000 / total_us,
+ total_bytes,
+ total_bytes * 1000 / total_us);
}
#else
#define dsi_perf_mark_setup()
#define dsi_perf_mark_start()
-#define dsi_perf_mark_start_auto()
#define dsi_perf_show(x)
#endif
@@ -774,7 +711,7 @@ static unsigned long dsi_fclk_rate(void)
{
unsigned long r;
- if (dss_get_dsi_clk_source() == 0) {
+ if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
/* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
r = dss_clk_get_rate(DSS_CLK_FCK1);
} else {
@@ -1227,17 +1164,19 @@ void dsi_dump_clocks(struct seq_file *s)
seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
cinfo->dsi1_pll_fclk,
cinfo->regm3,
- dss_get_dispc_clk_source() == 0 ? "off" : "on");
+ dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ "off" : "on");
seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
cinfo->dsi2_pll_fclk,
cinfo->regm4,
- dss_get_dsi_clk_source() == 0 ? "off" : "on");
+ dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ "off" : "on");
seq_printf(s, "- DSI -\n");
seq_printf(s, "dsi fclk source = %s\n",
- dss_get_dsi_clk_source() == 0 ?
+ 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());
@@ -1756,29 +1695,10 @@ static int dsi_force_tx_stop_mode_io(void)
return 0;
}
-static void dsi_vc_print_status(int channel)
-{
- u32 r;
-
- r = dsi_read_reg(DSI_VC_CTRL(channel));
- DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, "
- "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ",
- channel,
- FLD_GET(r, 5, 5),
- FLD_GET(r, 6, 6),
- FLD_GET(r, 15, 15),
- FLD_GET(r, 16, 16),
- FLD_GET(r, 20, 20));
-
- r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
- DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
-}
-
static int dsi_vc_enable(int channel, bool enable)
{
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("dsi_vc_enable channel %d, enable %d\n",
- channel, enable);
+ DSSDBG("dsi_vc_enable channel %d, enable %d\n",
+ channel, enable);
enable = enable ? 1 : 0;
@@ -1859,10 +1779,12 @@ static void dsi_vc_config_vp(int channel)
}
-static void dsi_vc_enable_hs(int channel, bool enable)
+void omapdss_dsi_vc_enable_hs(int channel, bool enable)
{
DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
+ WARN_ON(!dsi_bus_is_locked());
+
dsi_vc_enable(channel, 0);
dsi_if_enable(0);
@@ -1873,6 +1795,7 @@ static void dsi_vc_enable_hs(int channel, bool enable)
dsi_force_tx_stop_mode_io();
}
+EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
static void dsi_vc_flush_long_data(int channel)
{
@@ -1955,11 +1878,10 @@ static u16 dsi_vc_flush_receive_data(int channel)
static int dsi_vc_send_bta(int channel)
{
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO &&
- (dsi.debug_write || dsi.debug_read))
+ if (dsi.debug_write || dsi.debug_read)
DSSDBG("dsi_vc_send_bta %d\n", channel);
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
@@ -2010,10 +1932,9 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type,
u32 val;
u8 data_id;
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
- /*data_id = data_type | channel << 6; */
- data_id = data_type | dsi.vc[channel].dest_per << 6;
+ data_id = data_type | channel << 6;
val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
FLD_VAL(ecc, 31, 24);
@@ -2056,13 +1977,10 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
dsi_vc_write_long_header(channel, data_type, len, ecc);
- /*dsi_vc_print_status(0); */
-
p = data;
for (i = 0; i < len >> 2; i++) {
if (dsi.debug_write)
DSSDBG("\tsending full packet %d\n", i);
- /*dsi_vc_print_status(0); */
b1 = *p++;
b2 = *p++;
@@ -2105,7 +2023,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
u32 r;
u8 data_id;
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
if (dsi.debug_write)
DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
@@ -2119,7 +2037,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
return -EINVAL;
}
- data_id = data_type | dsi.vc[channel].dest_per << 6;
+ data_id = data_type | channel << 6;
r = (data_id << 0) | (data << 8) | (ecc << 24);
@@ -2163,14 +2081,35 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len)
r = dsi_vc_dcs_write_nosync(channel, data, len);
if (r)
- return r;
+ goto err;
r = dsi_vc_send_bta_sync(channel);
+ if (r)
+ goto err;
+ return 0;
+err:
+ DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
+ channel, data[0], len);
return r;
}
EXPORT_SYMBOL(dsi_vc_dcs_write);
+int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
+{
+ return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
+}
+EXPORT_SYMBOL(dsi_vc_dcs_write_0);
+
+int dsi_vc_dcs_write_1(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);
+}
+EXPORT_SYMBOL(dsi_vc_dcs_write_1);
+
int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
{
u32 val;
@@ -2182,16 +2121,17 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
if (r)
- return r;
+ goto err;
r = dsi_vc_send_bta_sync(channel);
if (r)
- return r;
+ goto err;
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
DSSERR("RX fifo empty when trying to read.\n");
- return -EIO;
+ r = -EIO;
+ goto err;
}
val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
@@ -2201,15 +2141,18 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dt == DSI_DT_RX_ACK_WITH_ERR) {
u16 err = FLD_GET(val, 23, 8);
dsi_show_rx_ack_with_err(err);
- return -EIO;
+ r = -EIO;
+ goto err;
} else if (dt == DSI_DT_RX_SHORT_READ_1) {
u8 data = FLD_GET(val, 15, 8);
if (dsi.debug_read)
DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
- if (buflen < 1)
- return -EIO;
+ if (buflen < 1) {
+ r = -EIO;
+ goto err;
+ }
buf[0] = data;
@@ -2219,8 +2162,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dsi.debug_read)
DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
- if (buflen < 2)
- return -EIO;
+ if (buflen < 2) {
+ r = -EIO;
+ goto err;
+ }
buf[0] = data & 0xff;
buf[1] = (data >> 8) & 0xff;
@@ -2232,8 +2177,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dsi.debug_read)
DSSDBG("\tDCS long response, len %d\n", len);
- if (len > buflen)
- return -EIO;
+ if (len > buflen) {
+ r = -EIO;
+ goto err;
+ }
/* two byte checksum ends the packet, not included in len */
for (w = 0; w < len + 2;) {
@@ -2255,14 +2202,52 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
}
return len;
-
} else {
DSSERR("\tunknown datatype 0x%02x\n", dt);
- return -EIO;
+ r = -EIO;
+ goto err;
}
+
+ BUG();
+err:
+ DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
+ channel, dcs_cmd);
+ return r;
+
}
EXPORT_SYMBOL(dsi_vc_dcs_read);
+int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
+{
+ int r;
+
+ r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
+
+ if (r < 0)
+ return r;
+
+ if (r != 1)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(dsi_vc_dcs_read_1);
+
+int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
+{
+ int r;
+
+ r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
+
+ if (r < 0)
+ return r;
+
+ if (r != 2)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(dsi_vc_dcs_read_2);
int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
{
@@ -2491,15 +2476,15 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
u32 r;
int buswidth = 0;
- dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0);
+ dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32);
- dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0);
+ dsi_config_rx_fifo(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);
@@ -2537,12 +2522,9 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_write_reg(DSI_CTRL, r);
dsi_vc_initial_config(0);
-
- /* set all vc targets to peripheral 0 */
- dsi.vc[0].dest_per = 0;
- dsi.vc[1].dest_per = 0;
- dsi.vc[2].dest_per = 0;
- dsi.vc[3].dest_per = 0;
+ dsi_vc_initial_config(1);
+ dsi_vc_initial_config(2);
+ dsi_vc_initial_config(3);
return 0;
}
@@ -2777,18 +2759,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
unsigned packet_payload;
unsigned packet_len;
u32 l;
- bool use_te_trigger;
- const unsigned channel = 0;
+ const unsigned channel = dsi.update_channel;
/* 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;
- use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
+ DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
+ x, y, w, h);
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
- x, y, w, h);
+ dsi_vc_config_vp(channel);
bytespp = dssdev->ctrl.pixel_size / 8;
bytespl = w * bytespp;
@@ -2808,15 +2788,12 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
if (bytespf % packet_payload)
total_len += (bytespf % packet_payload) + 1;
- if (0)
- dsi_vc_print_status(1);
-
l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
dsi_write_reg(DSI_VC_TE(channel), l);
dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
- if (use_te_trigger)
+ if (dsi.te_enabled)
l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
else
l = FLD_MOD(l, 1, 31, 31); /* TE_START */
@@ -2830,9 +2807,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
*/
dispc_disable_sidle();
+ dsi_perf_mark_start();
+
+ schedule_delayed_work(&dsi.framedone_timeout_work,
+ msecs_to_jiffies(250));
+
dss_start_update(dssdev);
- if (use_te_trigger) {
+ if (dsi.te_enabled) {
/* 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 */
@@ -2852,110 +2834,64 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif
-static void dsi_framedone_irq_callback(void *data, u32 mask)
+static void dsi_framedone_timeout_work_callback(struct work_struct *work)
{
- /* 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.
- */
+ int r;
+ const int channel = dsi.update_channel;
+
+ DSSERR("Framedone not received for 250ms!\n");
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
- dsi.framedone_received = true;
- wake_up(&dsi.waitqueue);
-}
-
-static void dsi_set_update_region(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- spin_lock(&dsi.update_lock);
- if (dsi.update_region.dirty) {
- dsi.update_region.x = min(x, dsi.update_region.x);
- dsi.update_region.y = min(y, dsi.update_region.y);
- dsi.update_region.w = max(w, dsi.update_region.w);
- dsi.update_region.h = max(h, dsi.update_region.h);
- } else {
- dsi.update_region.x = x;
- dsi.update_region.y = y;
- dsi.update_region.w = w;
- dsi.update_region.h = h;
+ if (dsi.te_enabled) {
+ /* enable LP_RX_TO again after the TE */
+ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
- dsi.update_region.device = dssdev;
- dsi.update_region.dirty = true;
-
- spin_unlock(&dsi.update_lock);
-
-}
-
-static int dsi_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- int r = 0;
- int i;
-
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
-
- if (dsi.update_mode != mode) {
- dsi.update_mode = mode;
-
- /* Mark the overlays dirty, and do apply(), so that we get the
- * overlays configured properly after update mode change. */
- 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;
- }
-
- r = dssdev->manager->apply(dssdev->manager);
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
- mode == OMAP_DSS_UPDATE_AUTO) {
- u16 w, h;
-
- DSSDBG("starting auto update\n");
-
- dssdev->get_resolution(dssdev, &w, &h);
-
- dsi_set_update_region(dssdev, 0, 0, w, h);
-
- dsi_perf_mark_start_auto();
+ /* 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(channel);
+ if (r)
+ DSSERR("BTA after framedone failed\n");
- wake_up(&dsi.waitqueue);
- }
+ /* 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);
}
- return r;
+ dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
}
-static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
+static void dsi_framedone_irq_callback(void *data, u32 mask)
{
- int r = 0;
+ /* 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.
+ */
- if (dssdev->driver->enable_te) {
- r = dssdev->driver->enable_te(dssdev, enable);
- /* XXX for some reason, DSI TE breaks if we don't wait here.
- * Panel bug? Needs more studying */
- msleep(100);
- }
+ /* SIDLEMODE back to smart-idle */
+ dispc_enable_sidle();
- return r;
+ schedule_work(&dsi.framedone_work);
}
static void dsi_handle_framedone(void)
{
int r;
- const int channel = 0;
- bool use_te_trigger;
-
- use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
+ const int channel = dsi.update_channel;
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("FRAMEDONE\n");
+ DSSDBG("FRAMEDONE\n");
- if (use_te_trigger) {
+ if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
@@ -2976,7 +2912,7 @@ static void dsi_handle_framedone(void)
/* 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(0);
+ dsi_vc_flush_receive_data(channel);
}
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
@@ -2984,118 +2920,79 @@ static void dsi_handle_framedone(void)
#endif
}
-static int dsi_update_thread(void *data)
+static void dsi_framedone_work_callback(struct work_struct *work)
{
- unsigned long timeout;
- struct omap_dss_device *device;
- u16 x, y, w, h;
-
- while (1) {
- bool sched;
-
- wait_event_interruptible(dsi.waitqueue,
- dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
- (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
- dsi.update_region.dirty == true) ||
- kthread_should_stop());
-
- if (kthread_should_stop())
- break;
-
- dsi_bus_lock();
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
- kthread_should_stop()) {
- dsi_bus_unlock();
- break;
- }
-
- dsi_perf_mark_setup();
-
- if (dsi.update_region.dirty) {
- spin_lock(&dsi.update_lock);
- dsi.active_update_region = dsi.update_region;
- dsi.update_region.dirty = false;
- spin_unlock(&dsi.update_lock);
- }
+ DSSDBGF();
- device = dsi.active_update_region.device;
- x = dsi.active_update_region.x;
- y = dsi.active_update_region.y;
- w = dsi.active_update_region.w;
- h = dsi.active_update_region.h;
+ cancel_delayed_work_sync(&dsi.framedone_timeout_work);
- if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
+ dsi_handle_framedone();
- if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL)
- dss_setup_partial_planes(device,
- &x, &y, &w, &h);
+ dsi_perf_show("DISPC");
- dispc_set_lcd_size(w, h);
- }
+ dsi.framedone_callback(0, dsi.framedone_data);
+}
- if (dsi.active_update_region.dirty) {
- dsi.active_update_region.dirty = false;
- /* XXX TODO we don't need to send the coords, if they
- * are the same that are already programmed to the
- * panel. That should speed up manual update a bit */
- device->driver->setup_update(device, x, y, w, h);
- }
+int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
+ u16 *x, u16 *y, u16 *w, u16 *h)
+{
+ u16 dw, dh;
- dsi_perf_mark_start();
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
- if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- dsi_vc_config_vp(0);
+ if (*x > dw || *y > dh)
+ return -EINVAL;
- if (dsi.te_enabled && dsi.use_ext_te)
- device->driver->wait_for_te(device);
+ if (*x + *w > dw)
+ return -EINVAL;
- dsi.framedone_received = false;
+ if (*y + *h > dh)
+ return -EINVAL;
- dsi_update_screen_dispc(device, x, y, w, h);
+ if (*w == 1)
+ return -EINVAL;
- /* wait for framedone */
- timeout = msecs_to_jiffies(1000);
- wait_event_timeout(dsi.waitqueue,
- dsi.framedone_received == true,
- timeout);
+ if (*w == 0 || *h == 0)
+ return -EINVAL;
- if (!dsi.framedone_received) {
- DSSERR("framedone timeout\n");
- DSSERR("failed update %d,%d %dx%d\n",
- x, y, w, h);
+ dsi_perf_mark_setup();
- dispc_enable_sidle();
- dispc_enable_lcd_out(0);
+ 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);
+ }
- dsi_reset_tx_fifo(0);
- } else {
- dsi_handle_framedone();
- dsi_perf_show("DISPC");
- }
- } else {
- dsi_update_screen_l4(device, x, y, w, h);
- dsi_perf_show("L4");
- }
+ return 0;
+}
+EXPORT_SYMBOL(omap_dsi_prepare_update);
- sched = atomic_read(&dsi.bus_lock.count) < 0;
+int omap_dsi_update(struct omap_dss_device *dssdev,
+ int channel,
+ u16 x, u16 y, u16 w, u16 h,
+ void (*callback)(int, void *), void *data)
+{
+ dsi.update_channel = channel;
- complete_all(&dsi.update_completion);
+ if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
+ dsi.framedone_callback = callback;
+ dsi.framedone_data = data;
- dsi_bus_unlock();
+ 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;
- /* XXX We need to give others chance to get the bus lock. Is
- * there a better way for this? */
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched)
- schedule_timeout_interruptible(1);
+ dsi_update_screen_dispc(dssdev, x, y, w, h);
+ } else {
+ dsi_update_screen_l4(dssdev, x, y, w, h);
+ dsi_perf_show("L4");
+ callback(0, data);
}
- DSSDBG("update thread exiting\n");
-
return 0;
}
-
-
+EXPORT_SYMBOL(omap_dsi_update);
/* Display funcs */
@@ -3203,7 +3100,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err1;
- dss_select_clk_source(true, true);
+ dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+ dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
DSSDBG("PLL OK\n");
@@ -3229,25 +3127,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
/* 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();
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err4;
- }
-
- /* enable high-speed after initial config */
- dsi_vc_enable_hs(0, 1);
-
return 0;
-err4:
- dsi_if_enable(0);
err3:
dsi_complexio_uninit();
err2:
- dss_select_clk_source(false, false);
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
err1:
dsi_pll_uninit();
err0:
@@ -3256,10 +3147,8 @@ err0:
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
{
- if (dssdev->driver->disable)
- dssdev->driver->disable(dssdev);
-
- dss_select_clk_source(false, false);
+ 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();
}
@@ -3280,14 +3169,15 @@ static int dsi_core_init(void)
return 0;
}
-static int dsi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{
int r = 0;
DSSDBG("dsi_display_enable\n");
+ WARN_ON(!dsi_bus_is_locked());
+
mutex_lock(&dsi.lock);
- dsi_bus_lock();
r = omap_dss_start_device(dssdev);
if (r) {
@@ -3295,100 +3185,47 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("dssdev already enabled\n");
- r = -EINVAL;
- goto err1;
- }
-
enable_clocks(1);
dsi_enable_pll_clock(1);
r = _dsi_reset();
if (r)
- goto err2;
+ goto err1;
dsi_core_init();
r = dsi_display_init_dispc(dssdev);
if (r)
- goto err2;
+ goto err1;
r = dsi_display_init_dsi(dssdev);
if (r)
- goto err3;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- dsi.use_ext_te = dssdev->phy.dsi.ext_te;
- r = dsi_set_te(dssdev, dsi.te_enabled);
- if (r)
- goto err4;
-
- dsi_set_update_mode(dssdev, dsi.user_update_mode);
+ goto err2;
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
return 0;
-err4:
-
- dsi_display_uninit_dsi(dssdev);
-err3:
- dsi_display_uninit_dispc(dssdev);
err2:
+ dsi_display_uninit_dispc(dssdev);
+err1:
enable_clocks(0);
dsi_enable_pll_clock(0);
-err1:
omap_dss_stop_device(dssdev);
err0:
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
DSSDBG("dsi_display_enable FAILED\n");
return r;
}
+EXPORT_SYMBOL(omapdss_dsi_display_enable);
-static void dsi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
{
DSSDBG("dsi_display_disable\n");
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
- dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- goto end;
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
- dsi_display_uninit_dispc(dssdev);
-
- dsi_display_uninit_dsi(dssdev);
-
- enable_clocks(0);
- dsi_enable_pll_clock(0);
-
- omap_dss_stop_device(dssdev);
-end:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-}
-
-static int dsi_display_suspend(struct omap_dss_device *dssdev)
-{
- DSSDBG("dsi_display_suspend\n");
+ WARN_ON(!dsi_bus_is_locked());
mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
- dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- goto end;
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
dsi_display_uninit_dispc(dssdev);
@@ -3396,312 +3233,19 @@ static int dsi_display_suspend(struct omap_dss_device *dssdev)
enable_clocks(0);
dsi_enable_pll_clock(0);
-end:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- return 0;
-}
-
-static int dsi_display_resume(struct omap_dss_device *dssdev)
-{
- int r;
-
- DSSDBG("dsi_display_resume\n");
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
- DSSERR("dssdev not suspended\n");
- r = -EINVAL;
- goto err0;
- }
-
- enable_clocks(1);
- dsi_enable_pll_clock(1);
-
- r = _dsi_reset();
- if (r)
- goto err1;
-
- dsi_core_init();
-
- r = dsi_display_init_dispc(dssdev);
- if (r)
- goto err1;
-
- r = dsi_display_init_dsi(dssdev);
- if (r)
- goto err2;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- r = dsi_set_te(dssdev, dsi.te_enabled);
- if (r)
- goto err2;
-
- dsi_set_update_mode(dssdev, dsi.user_update_mode);
-
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- return 0;
-
-err2:
- dsi_display_uninit_dispc(dssdev);
-err1:
- enable_clocks(0);
- dsi_enable_pll_clock(0);
-err0:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
- DSSDBG("dsi_display_resume FAILED\n");
- return r;
-}
-
-static int dsi_display_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- int r = 0;
- u16 dw, dh;
-
- DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
- mutex_lock(&dsi.lock);
-
- if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
- goto end;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- goto end;
-
- dssdev->get_resolution(dssdev, &dw, &dh);
-
- if (x > dw || y > dh)
- goto end;
-
- if (x + w > dw)
- w = dw - x;
-
- if (y + h > dh)
- h = dh - y;
-
- if (w == 0 || h == 0)
- goto end;
-
- if (w == 1) {
- r = -EINVAL;
- goto end;
- }
-
- dsi_set_update_region(dssdev, x, y, w, h);
-
- wake_up(&dsi.waitqueue);
-
-end:
- mutex_unlock(&dsi.lock);
-
- return r;
-}
-
-static int dsi_display_sync(struct omap_dss_device *dssdev)
-{
- bool wait;
-
- DSSDBG("dsi_display_sync()\n");
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
- dsi.update_region.dirty) {
- INIT_COMPLETION(dsi.update_completion);
- wait = true;
- } else {
- wait = false;
- }
-
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- if (wait)
- wait_for_completion_interruptible(&dsi.update_completion);
-
- DSSDBG("dsi_display_sync() done\n");
- return 0;
-}
-
-static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- int r = 0;
-
- DSSDBGF("%d", mode);
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- dsi.user_update_mode = mode;
- r = dsi_set_update_mode(dssdev, mode);
+ omap_dss_stop_device(dssdev);
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
-
- return r;
}
+EXPORT_SYMBOL(omapdss_dsi_display_disable);
-static enum omap_dss_update_mode dsi_display_get_update_mode(
- struct omap_dss_device *dssdev)
+int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
{
- return dsi.update_mode;
-}
-
-
-static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
-{
- int r = 0;
-
- DSSDBGF("%d", enable);
-
- if (!dssdev->driver->enable_te)
- return -ENOENT;
-
- dsi_bus_lock();
-
dsi.te_enabled = enable;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- goto end;
-
- r = dsi_set_te(dssdev, enable);
-end:
- dsi_bus_unlock();
-
- return r;
-}
-
-static int dsi_display_get_te(struct omap_dss_device *dssdev)
-{
- return dsi.te_enabled;
-}
-
-static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
-{
-
- DSSDBGF("%d", rotate);
-
- if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
- return -EINVAL;
-
- dsi_bus_lock();
- dssdev->driver->set_rotate(dssdev, rotate);
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
- u16 w, h;
- /* the display dimensions may have changed, so set a new
- * update region */
- dssdev->get_resolution(dssdev, &w, &h);
- dsi_set_update_region(dssdev, 0, 0, w, h);
- }
- dsi_bus_unlock();
-
return 0;
}
-
-static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
-{
- if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
- return 0;
-
- return dssdev->driver->get_rotate(dssdev);
-}
-
-static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
-{
- DSSDBGF("%d", mirror);
-
- if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
- return -EINVAL;
-
- dsi_bus_lock();
- dssdev->driver->set_mirror(dssdev, mirror);
- dsi_bus_unlock();
-
- return 0;
-}
-
-static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
-{
- if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
- return 0;
-
- return dssdev->driver->get_mirror(dssdev);
-}
-
-static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
-{
- int r;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EIO;
-
- DSSDBGF("%d", test_num);
-
- dsi_bus_lock();
-
- /* run test first in low speed mode */
- dsi_vc_enable_hs(0, 0);
-
- if (dssdev->driver->run_test) {
- r = dssdev->driver->run_test(dssdev, test_num);
- if (r)
- goto end;
- }
-
- /* then in high speed */
- dsi_vc_enable_hs(0, 1);
-
- if (dssdev->driver->run_test) {
- r = dssdev->driver->run_test(dssdev, test_num);
- if (r)
- goto end;
- }
-
-end:
- dsi_vc_enable_hs(0, 1);
-
- dsi_bus_unlock();
-
- return r;
-}
-
-static int dsi_display_memory_read(struct omap_dss_device *dssdev,
- void *buf, size_t size,
- u16 x, u16 y, u16 w, u16 h)
-{
- int r;
-
- DSSDBGF("");
-
- if (!dssdev->driver->memory_read)
- return -EINVAL;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EIO;
-
- dsi_bus_lock();
-
- r = dssdev->driver->memory_read(dssdev, buf, size,
- x, y, w, h);
-
- /* Memory read usually changes the update area. This will
- * force the next update to re-set the update area */
- dsi.active_update_region.dirty = true;
-
- dsi_bus_unlock();
-
- return r;
-}
+EXPORT_SYMBOL(omapdss_dsi_enable_te);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
@@ -3720,26 +3264,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("DSI init\n");
- dssdev->enable = dsi_display_enable;
- dssdev->disable = dsi_display_disable;
- dssdev->suspend = dsi_display_suspend;
- dssdev->resume = dsi_display_resume;
- dssdev->update = dsi_display_update;
- dssdev->sync = dsi_display_sync;
- dssdev->set_update_mode = dsi_display_set_update_mode;
- dssdev->get_update_mode = dsi_display_get_update_mode;
- dssdev->enable_te = dsi_display_enable_te;
- dssdev->get_te = dsi_display_get_te;
-
- dssdev->get_rotate = dsi_display_get_rotate;
- dssdev->set_rotate = dsi_display_set_rotate;
-
- dssdev->get_mirror = dsi_display_get_mirror;
- dssdev->set_mirror = dsi_display_set_mirror;
-
- dssdev->run_test = dsi_display_run_test;
- dssdev->memory_read = dsi_display_memory_read;
-
/* XXX these should be figured out dynamically */
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
@@ -3754,9 +3278,6 @@ int dsi_init(struct platform_device *pdev)
{
u32 rev;
int r;
- struct sched_param param = {
- .sched_priority = MAX_USER_RT_PRIO-1
- };
spin_lock_init(&dsi.errors_lock);
dsi.errors = 0;
@@ -3767,31 +3288,19 @@ int dsi_init(struct platform_device *pdev)
#endif
init_completion(&dsi.bta_completion);
- init_completion(&dsi.update_completion);
-
- dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
- if (IS_ERR(dsi.thread)) {
- DSSERR("cannot create kthread\n");
- r = PTR_ERR(dsi.thread);
- goto err0;
- }
- sched_setscheduler(dsi.thread, SCHED_FIFO, &param);
-
- init_waitqueue_head(&dsi.waitqueue);
- spin_lock_init(&dsi.update_lock);
mutex_init(&dsi.lock);
- mutex_init(&dsi.bus_lock);
+ sema_init(&dsi.bus_lock, 1);
+
+ INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
+ INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
+ dsi_framedone_timeout_work_callback);
#ifdef DSI_CATCH_MISSING_TE
init_timer(&dsi.te_timer);
dsi.te_timer.function = dsi_te_timeout;
dsi.te_timer.data = 0;
#endif
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
-
dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
if (!dsi.base) {
DSSERR("can't ioremap DSI\n");
@@ -3799,7 +3308,7 @@ int dsi_init(struct platform_device *pdev)
goto err1;
}
- dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi");
+ 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");
@@ -3815,23 +3324,15 @@ int dsi_init(struct platform_device *pdev)
enable_clocks(0);
- wake_up_process(dsi.thread);
-
return 0;
err2:
iounmap(dsi.base);
err1:
- kthread_stop(dsi.thread);
-err0:
return r;
}
void dsi_exit(void)
{
- kthread_stop(dsi.thread);
-
- regulator_put(dsi.vdds_dsi_reg);
-
iounmap(dsi.base);
DSSDBG("omap_dsi_exit\n");
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 0a26b7d84d41..8254a4232a53 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -68,6 +68,9 @@ static struct {
struct dss_clock_info cache_dss_cinfo;
struct dispc_clock_info cache_dispc_cinfo;
+ enum dss_clk_source dsi_clk_source;
+ enum dss_clk_source dispc_clk_source;
+
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
} dss;
@@ -247,23 +250,42 @@ void dss_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-void dss_select_clk_source(bool dsi, bool dispc)
+void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+{
+ int b;
+
+ BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
+ clk_src != DSS_SRC_DSS1_ALWON_FCLK);
+
+ b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
+
+ REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
+
+ dss.dispc_clk_source = clk_src;
+}
+
+void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
{
- u32 r;
- r = dss_read_reg(DSS_CONTROL);
- r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
- r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
- dss_write_reg(DSS_CONTROL, r);
+ int b;
+
+ BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
+ clk_src != DSS_SRC_DSS1_ALWON_FCLK);
+
+ b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
+
+ REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
+
+ dss.dsi_clk_source = clk_src;
}
-int dss_get_dsi_clk_source(void)
+enum dss_clk_source dss_get_dispc_clk_source(void)
{
- return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
+ return dss.dispc_clk_source;
}
-int dss_get_dispc_clk_source(void)
+enum dss_clk_source dss_get_dsi_clk_source(void)
{
- return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
+ return dss.dsi_clk_source;
}
/* calculate clock rates using dividers in cinfo */
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 2bcb1245d6c2..24326a5fd292 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -119,6 +119,12 @@ enum dss_clock {
DSS_CLK_96M = 1 << 4,
};
+enum dss_clk_source {
+ DSS_SRC_DSI1_PLL_FCLK,
+ DSS_SRC_DSI2_PLL_FCLK,
+ DSS_SRC_DSS1_ALWON_FCLK,
+};
+
struct dss_clock_info {
/* rates that we get with dividers below */
unsigned long fck;
@@ -169,6 +175,9 @@ unsigned long dss_clk_get_rate(enum dss_clock clk);
int dss_need_ctx_restore(void);
void dss_dump_clocks(struct seq_file *s);
struct bus_type *dss_get_bus(void);
+struct regulator *dss_get_vdds_dsi(void);
+struct regulator *dss_get_vdds_sdi(void);
+struct regulator *dss_get_vdda_dac(void);
/* display */
int dss_suspend_all_devices(void);
@@ -216,9 +225,11 @@ void dss_sdi_init(u8 datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
-void dss_select_clk_source(bool dsi, bool dispc);
-int dss_get_dsi_clk_source(void);
-int dss_get_dispc_clk_source(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);
+enum dss_clk_source dss_get_dispc_clk_source(void);
+enum dss_clk_source dss_get_dsi_clk_source(void);
+
void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
@@ -261,7 +272,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high);
/* DPI */
-int dpi_init(void);
+int dpi_init(struct platform_device *pdev);
void dpi_exit(void);
int dpi_init_display(struct omap_dss_device *dssdev);
@@ -313,8 +324,8 @@ int dispc_setup_plane(enum omap_plane plane,
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
-void dispc_enable_lcd_out(bool enable);
-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);
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 27d9c465c851..913142d4cab1 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -501,6 +501,19 @@ static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
return 0;
}
+static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
+{
+ unsigned long timeout = msecs_to_jiffies(500);
+ u32 irq;
+
+ if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+ irq = DISPC_IRQ_EVSYNC_ODD;
+ else
+ irq = DISPC_IRQ_VSYNC;
+
+ return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+}
+
static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
@@ -509,17 +522,18 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
u32 irq;
int r;
int i;
+ struct omap_dss_device *dssdev = mgr->device;
- if (!mgr->device)
+ if (!dssdev)
return 0;
- if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
- if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+ if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
- mode = mgr->device->get_update_mode(mgr->device);
+ mode = dssdev->driver->get_update_mode(dssdev);
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
@@ -592,7 +606,7 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
- mode = dssdev->get_update_mode(dssdev);
+ mode = dssdev->driver->get_update_mode(dssdev);
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
@@ -1064,7 +1078,7 @@ void dss_start_update(struct omap_dss_device *dssdev)
mc->shadow_dirty = false;
}
- dispc_enable_lcd_out(1);
+ dssdev->manager->enable(dssdev->manager);
}
static void dss_apply_irq_handler(void *data, u32 mask)
@@ -1196,7 +1210,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->manual_update =
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
- dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+ dssdev->driver->get_update_mode(dssdev) !=
+ OMAP_DSS_UPDATE_AUTO;
++num_planes_enabled;
}
@@ -1237,7 +1252,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
mc->manual_update =
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
- dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+ dssdev->driver->get_update_mode(dssdev) !=
+ OMAP_DSS_UPDATE_AUTO;
}
/* XXX TODO: Try to get fifomerge working. The problem is that it
@@ -1351,6 +1367,18 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
*info = mgr->info;
}
+static int dss_mgr_enable(struct omap_overlay_manager *mgr)
+{
+ dispc_enable_channel(mgr->id, 1);
+ return 0;
+}
+
+static int dss_mgr_disable(struct omap_overlay_manager *mgr)
+{
+ dispc_enable_channel(mgr->id, 0);
+ return 0;
+}
+
static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
{
++num_managers;
@@ -1394,6 +1422,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
mgr->set_manager_info = &omap_dss_mgr_set_info;
mgr->get_manager_info = &omap_dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
+ mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
+
+ mgr->enable = &dss_mgr_enable;
+ mgr->disable = &dss_mgr_disable;
mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index b7f9a7339842..0c5bea263ac6 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -350,7 +350,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
return -EINVAL;
}
- dssdev->get_resolution(dssdev, &dw, &dh);
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
ovl->id,
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index b936495c065d..cc23f53cc62d 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -36,8 +36,6 @@
#include <plat/display.h>
#include "dss.h"
-/*#define MEASURE_PERF*/
-
#define RFBI_BASE 0x48050800
struct rfbi_reg { u16 idx; };
@@ -66,8 +64,6 @@ struct rfbi_reg { u16 idx; };
#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
-#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
-
#define REG_FLD_MOD(idx, val, start, end) \
rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
@@ -102,7 +98,6 @@ enum update_cmd {
static int rfbi_convert_timings(struct rfbi_timings *t);
static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
-static void process_cmd_fifo(void);
static struct {
void __iomem *base;
@@ -125,11 +120,6 @@ static struct {
struct completion cmd_done;
atomic_t cmd_fifo_full;
atomic_t cmd_pending;
-#ifdef MEASURE_PERF
- unsigned perf_bytes;
- ktime_t perf_setup_time;
- ktime_t perf_start_time;
-#endif
} rfbi;
struct update_region {
@@ -139,16 +129,6 @@ struct update_region {
u16 h;
};
-struct update_param {
- u8 rfbi_module;
- u8 cmd;
-
- union {
- struct update_region r;
- struct completion *sync;
- } par;
-};
-
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
{
__raw_writel(val, rfbi.base + idx.idx);
@@ -321,55 +301,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
-#ifdef MEASURE_PERF
-static void perf_mark_setup(void)
-{
- rfbi.perf_setup_time = ktime_get();
-}
-
-static void perf_mark_start(void)
-{
- rfbi.perf_start_time = ktime_get();
-}
-
-static void perf_show(const char *name)
-{
- ktime_t t, setup_time, trans_time;
- u32 total_bytes;
- u32 setup_us, trans_us, total_us;
-
- t = ktime_get();
-
- setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
- setup_us = (u32)ktime_to_us(setup_time);
- if (setup_us == 0)
- setup_us = 1;
-
- trans_time = ktime_sub(t, rfbi.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 = rfbi.perf_bytes;
-
- DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
- "%u kbytes/sec\n",
- name,
- setup_us,
- trans_us,
- total_us,
- 1000*1000 / total_us,
- total_bytes,
- total_bytes * 1000 / total_us);
-}
-#else
-#define perf_mark_setup()
-#define perf_mark_start()
-#define perf_show(x)
-#endif
-
void rfbi_transfer_area(u16 width, u16 height,
void (callback)(void *data), void *data)
{
@@ -382,7 +313,7 @@ void rfbi_transfer_area(u16 width, u16 height,
dispc_set_lcd_size(width, height);
- dispc_enable_lcd_out(1);
+ dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
rfbi.framedone_callback = callback;
rfbi.framedone_callback_data = data;
@@ -396,8 +327,6 @@ void rfbi_transfer_area(u16 width, u16 height,
if (!rfbi.te_enabled)
l = FLD_MOD(l, 1, 4, 4); /* ITE */
- perf_mark_start();
-
rfbi_write_reg(RFBI_CONTROL, l);
}
@@ -407,8 +336,6 @@ static void framedone_callback(void *data, u32 mask)
DSSDBG("FRAMEDONE\n");
- perf_show("DISPC");
-
REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
rfbi_enable_clocks(0);
@@ -416,11 +343,10 @@ static void framedone_callback(void *data, u32 mask)
callback = rfbi.framedone_callback;
rfbi.framedone_callback = NULL;
- /*callback(rfbi.framedone_callback_data);*/
+ if (callback != NULL)
+ callback(rfbi.framedone_callback_data);
atomic_set(&rfbi.cmd_pending, 0);
-
- process_cmd_fifo();
}
#if 1 /* VERBOSE */
@@ -937,52 +863,43 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
}
EXPORT_SYMBOL(rfbi_configure);
-static int rfbi_find_display(struct omap_dss_device *dssdev)
+int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
+ u16 *x, u16 *y, u16 *w, u16 *h)
{
- if (dssdev == rfbi.dssdev[0])
- return 0;
+ u16 dw, dh;
- if (dssdev == rfbi.dssdev[1])
- return 1;
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
- BUG();
- return -1;
-}
+ if (*x > dw || *y > dh)
+ return -EINVAL;
+ if (*x + *w > dw)
+ return -EINVAL;
-static void signal_fifo_waiters(void)
-{
- if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
- /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
- complete(&rfbi.cmd_done);
- atomic_dec(&rfbi.cmd_fifo_full);
- }
-}
+ if (*y + *h > dh)
+ return -EINVAL;
-/* returns 1 for async op, and 0 for sync op */
-static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
-{
- u16 x = upd->x;
- u16 y = upd->y;
- u16 w = upd->w;
- u16 h = upd->h;
+ if (*w == 1)
+ return -EINVAL;
- perf_mark_setup();
+ if (*w == 0 || *h == 0)
+ return -EINVAL;
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- /*dssdev->driver->enable_te(dssdev, 1); */
- dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
+ dss_setup_partial_planes(dssdev, x, y, w, h);
+ dispc_set_lcd_size(*w, *h);
}
-#ifdef MEASURE_PERF
- rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
-#endif
-
- dssdev->driver->setup_update(dssdev, x, y, w, h);
+ return 0;
+}
+EXPORT_SYMBOL(omap_rfbi_prepare_update);
+int omap_rfbi_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h,
+ void (*callback)(void *), void *data)
+{
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- rfbi_transfer_area(w, h, NULL, NULL);
- return 1;
+ rfbi_transfer_area(w, h, callback, data);
} else {
struct omap_overlay *ovl;
void __iomem *addr;
@@ -994,123 +911,12 @@ static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
- perf_show("L4");
-
- return 0;
+ callback(data);
}
-}
-
-static void process_cmd_fifo(void)
-{
- int len;
- struct update_param p;
- struct omap_dss_device *dssdev;
- unsigned long flags;
-
- if (atomic_inc_return(&rfbi.cmd_pending) != 1)
- return;
-
- while (true) {
- spin_lock_irqsave(&rfbi.cmd_lock, flags);
-
- len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p,
- sizeof(struct update_param));
- if (len == 0) {
- DSSDBG("nothing more in fifo\n");
- atomic_set(&rfbi.cmd_pending, 0);
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
- break;
- }
-
- /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
-
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
-
- BUG_ON(len != sizeof(struct update_param));
- BUG_ON(p.rfbi_module > 1);
-
- dssdev = rfbi.dssdev[p.rfbi_module];
-
- if (p.cmd == RFBI_CMD_UPDATE) {
- if (do_update(dssdev, &p.par.r))
- break; /* async op */
- } else if (p.cmd == RFBI_CMD_SYNC) {
- DSSDBG("Signaling SYNC done!\n");
- complete(p.par.sync);
- } else
- BUG();
- }
-
- signal_fifo_waiters();
-}
-static void rfbi_push_cmd(struct update_param *p)
-{
- int ret;
-
- while (1) {
- unsigned long flags;
- int available;
-
- spin_lock_irqsave(&rfbi.cmd_lock, flags);
- available = RFBI_CMD_FIFO_LEN_BYTES -
- kfifo_len(&rfbi.cmd_fifo);
-
-/* DSSDBG("%d bytes left in fifo\n", available); */
- if (available < sizeof(struct update_param)) {
- DSSDBG("Going to wait because FIFO FULL..\n");
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
- atomic_inc(&rfbi.cmd_fifo_full);
- wait_for_completion(&rfbi.cmd_done);
- /*DSSDBG("Woke up because fifo not full anymore\n");*/
- continue;
- }
-
- ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p,
- sizeof(struct update_param));
-/* DSSDBG("pushed %d bytes\n", ret);*/
-
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
-
- BUG_ON(ret != sizeof(struct update_param));
-
- break;
- }
-}
-
-static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
-{
- struct update_param p;
-
- p.rfbi_module = rfbi_module;
- p.cmd = RFBI_CMD_UPDATE;
-
- p.par.r.x = x;
- p.par.r.y = y;
- p.par.r.w = w;
- p.par.r.h = h;
-
- DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
-
- rfbi_push_cmd(&p);
-
- process_cmd_fifo();
-}
-
-static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
-{
- struct update_param p;
-
- p.rfbi_module = rfbi_module;
- p.cmd = RFBI_CMD_SYNC;
- p.par.sync = sync_comp;
-
- rfbi_push_cmd(&p);
-
- DSSDBG("RFBI sync pushed to cmd fifo\n");
-
- process_cmd_fifo();
+ return 0;
}
+EXPORT_SYMBOL(omap_rfbi_update);
void rfbi_dump_regs(struct seq_file *s)
{
@@ -1155,12 +961,8 @@ int rfbi_init(void)
{
u32 rev;
u32 l;
- int r;
spin_lock_init(&rfbi.cmd_lock);
- r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL);
- if (r)
- return r;
init_completion(&rfbi.cmd_done);
atomic_set(&rfbi.cmd_fifo_full, 0);
@@ -1196,49 +998,10 @@ void rfbi_exit(void)
{
DSSDBG("rfbi_exit\n");
- kfifo_free(&rfbi.cmd_fifo);
-
iounmap(rfbi.base);
}
-/* struct omap_display support */
-static int rfbi_display_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- int rfbi_module;
-
- if (w == 0 || h == 0)
- return 0;
-
- rfbi_module = rfbi_find_display(dssdev);
-
- rfbi_push_update(rfbi_module, x, y, w, h);
-
- return 0;
-}
-
-static int rfbi_display_sync(struct omap_dss_device *dssdev)
-{
- struct completion sync_comp;
- int rfbi_module;
-
- rfbi_module = rfbi_find_display(dssdev);
-
- init_completion(&sync_comp);
- rfbi_push_sync(rfbi_module, &sync_comp);
- DSSDBG("Waiting for SYNC to happen...\n");
- wait_for_completion(&sync_comp);
- DSSDBG("Released from SYNC\n");
- return 0;
-}
-
-static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
-{
- dssdev->driver->enable_te(dssdev, enable);
- return 0;
-}
-
-static int rfbi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
int r;
@@ -1269,41 +1032,25 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev)
&dssdev->ctrl.rfbi_timings);
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err2;
- }
-
return 0;
-err2:
- omap_dispc_unregister_isr(framedone_callback, NULL,
- DISPC_IRQ_FRAMEDONE);
err1:
omap_dss_stop_device(dssdev);
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_rfbi_display_enable);
-static void rfbi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
{
- dssdev->driver->disable(dssdev);
omap_dispc_unregister_isr(framedone_callback, NULL,
DISPC_IRQ_FRAMEDONE);
omap_dss_stop_device(dssdev);
}
+EXPORT_SYMBOL(omapdss_rfbi_display_disable);
int rfbi_init_display(struct omap_dss_device *dssdev)
{
- dssdev->enable = rfbi_display_enable;
- dssdev->disable = rfbi_display_disable;
- dssdev->update = rfbi_display_update;
- dssdev->sync = rfbi_display_sync;
- dssdev->enable_te = rfbi_display_enable_te;
-
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
-
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
-
return 0;
}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index c24f307d3da1..12eb4042dd82 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -41,7 +41,7 @@ static void sdi_basic_init(void)
dispc_lcd_enable_signal_polarity(1);
}
-static int sdi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_video_timings *t = &dssdev->panel.timings;
struct dss_clock_info dss_cinfo;
@@ -57,12 +57,6 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("dssdev already enabled\n");
- r = -EINVAL;
- 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);
@@ -119,7 +113,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
}
- dispc_enable_lcd_out(1);
+ dssdev->manager->enable(dssdev->manager);
if (dssdev->driver->enable) {
r = dssdev->driver->enable(dssdev);
@@ -127,13 +121,11 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
goto err3;
}
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
sdi.skip_init = 0;
return 0;
err3:
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
err1:
@@ -141,120 +133,27 @@ err1:
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_sdi_display_enable);
-static int sdi_display_resume(struct omap_dss_device *dssdev);
-
-static void sdi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- return;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- if (sdi_display_resume(dssdev))
- return;
-
if (dssdev->driver->disable)
dssdev->driver->disable(dssdev);
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
omap_dss_stop_device(dssdev);
}
-
-static int sdi_display_suspend(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
-
- if (dssdev->driver->suspend)
- dssdev->driver->suspend(dssdev);
-
- dispc_enable_lcd_out(0);
-
- dss_sdi_disable();
-
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
- return 0;
-}
-
-static int sdi_display_resume(struct omap_dss_device *dssdev)
-{
- int r;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
-
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- r = dss_sdi_enable();
- if (r)
- goto err;
- mdelay(2);
-
- dispc_enable_lcd_out(1);
-
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-err:
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- return r;
-}
-
-static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- if (mode == OMAP_DSS_UPDATE_MANUAL)
- return -EINVAL;
-
- if (mode == OMAP_DSS_UPDATE_DISABLED) {
- dispc_enable_lcd_out(0);
- sdi.update_enabled = 0;
- } else {
- dispc_enable_lcd_out(1);
- sdi.update_enabled = 1;
- }
-
- return 0;
-}
-
-static enum omap_dss_update_mode sdi_display_get_update_mode(
- struct omap_dss_device *dssdev)
-{
- return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
- OMAP_DSS_UPDATE_DISABLED;
-}
-
-static void sdi_get_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- *timings = dssdev->panel.timings;
-}
+EXPORT_SYMBOL(omapdss_sdi_display_disable);
int sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
- dssdev->enable = sdi_display_enable;
- dssdev->disable = sdi_display_disable;
- dssdev->suspend = sdi_display_suspend;
- dssdev->resume = sdi_display_resume;
- dssdev->set_update_mode = sdi_display_set_update_mode;
- dssdev->get_update_mode = sdi_display_get_update_mode;
- dssdev->get_timings = sdi_get_timings;
-
return 0;
}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 749a5a0f5be4..f0ba5732d84a 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -400,114 +400,6 @@ static const struct venc_config *venc_timings_to_config(
BUG();
}
-
-
-
-
-/* driver */
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.timings = omap_dss_pal_timings;
-
- return 0;
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- /* wait couple of vsyncs until enabling the LCD */
- msleep(50);
-
- if (dssdev->platform_enable)
- r = dssdev->platform_enable(dssdev);
-
- return r;
-}
-
-static void venc_panel_disable(struct omap_dss_device *dssdev)
-{
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- /* wait at least 5 vsyncs after disabling the LCD */
-
- msleep(100);
-}
-
-static int venc_panel_suspend(struct omap_dss_device *dssdev)
-{
- venc_panel_disable(dssdev);
- return 0;
-}
-
-static int venc_panel_resume(struct omap_dss_device *dssdev)
-{
- return venc_panel_enable(dssdev);
-}
-
-static struct omap_dss_driver venc_driver = {
- .probe = venc_panel_probe,
- .remove = venc_panel_remove,
-
- .enable = venc_panel_enable,
- .disable = venc_panel_disable,
- .suspend = venc_panel_suspend,
- .resume = venc_panel_resume,
-
- .driver = {
- .name = "venc",
- .owner = THIS_MODULE,
- },
-};
-/* driver end */
-
-
-
-int venc_init(struct platform_device *pdev)
-{
- u8 rev_id;
-
- mutex_init(&venc.venc_lock);
-
- venc.wss_data = 0;
-
- venc.base = ioremap(VENC_BASE, SZ_1K);
- if (!venc.base) {
- DSSERR("can't ioremap VENC\n");
- return -ENOMEM;
- }
-
- venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
- if (IS_ERR(venc.vdda_dac_reg)) {
- iounmap(venc.base);
- DSSERR("can't get VDDA_DAC regulator\n");
- return PTR_ERR(venc.vdda_dac_reg);
- }
-
- venc_enable_clocks(1);
-
- rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
- printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
-
- venc_enable_clocks(0);
-
- return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_exit(void)
-{
- omap_dss_unregister_driver(&venc_driver);
-
- regulator_put(venc.vdda_dac_reg);
-
- iounmap(venc.base);
-}
-
static void venc_power_on(struct omap_dss_device *dssdev)
{
u32 l;
@@ -540,7 +432,7 @@ static void venc_power_on(struct omap_dss_device *dssdev)
if (dssdev->platform_enable)
dssdev->platform_enable(dssdev);
- dispc_enable_digit_out(1);
+ dssdev->manager->enable(dssdev->manager);
}
static void venc_power_off(struct omap_dss_device *dssdev)
@@ -548,7 +440,7 @@ static void venc_power_off(struct omap_dss_device *dssdev)
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- dispc_enable_digit_out(0);
+ dssdev->manager->disable(dssdev->manager);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
@@ -558,7 +450,23 @@ static void venc_power_off(struct omap_dss_device *dssdev)
venc_enable_clocks(0);
}
-static int venc_enable_display(struct omap_dss_device *dssdev)
+
+
+
+
+/* driver */
+static int venc_panel_probe(struct omap_dss_device *dssdev)
+{
+ dssdev->panel.timings = omap_dss_pal_timings;
+
+ return 0;
+}
+
+static void venc_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int venc_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
@@ -568,7 +476,13 @@ static int venc_enable_display(struct omap_dss_device *dssdev)
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
r = -EINVAL;
- goto err;
+ goto err1;
+ }
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err2;
}
venc_power_on(dssdev);
@@ -576,13 +490,21 @@ static int venc_enable_display(struct omap_dss_device *dssdev)
venc.wss_data = 0;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-err:
+
+ /* 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;
}
-static void venc_disable_display(struct omap_dss_device *dssdev)
+static void venc_panel_disable(struct omap_dss_device *dssdev)
{
DSSDBG("venc_disable_display\n");
@@ -599,53 +521,40 @@ static void venc_disable_display(struct omap_dss_device *dssdev)
venc_power_off(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);
}
-static int venc_display_suspend(struct omap_dss_device *dssdev)
+static int venc_panel_suspend(struct omap_dss_device *dssdev)
{
- int r = 0;
-
- DSSDBG("venc_display_suspend\n");
-
- mutex_lock(&venc.venc_lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
- r = -EINVAL;
- goto err;
- }
-
- venc_power_off(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-err:
- mutex_unlock(&venc.venc_lock);
-
- return r;
+ venc_panel_disable(dssdev);
+ return 0;
}
-static int venc_display_resume(struct omap_dss_device *dssdev)
+static int venc_panel_resume(struct omap_dss_device *dssdev)
{
- int r = 0;
-
- DSSDBG("venc_display_resume\n");
-
- mutex_lock(&venc.venc_lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
- r = -EINVAL;
- goto err;
- }
-
- venc_power_on(dssdev);
+ return venc_panel_enable(dssdev);
+}
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-err:
- mutex_unlock(&venc.venc_lock);
+static enum omap_dss_update_mode venc_get_update_mode(
+ struct omap_dss_device *dssdev)
+{
+ return OMAP_DSS_UPDATE_AUTO;
+}
- return r;
+static int venc_set_update_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_update_mode mode)
+{
+ if (mode != OMAP_DSS_UPDATE_AUTO)
+ return -EINVAL;
+ return 0;
}
static void venc_get_timings(struct omap_dss_device *dssdev,
@@ -666,8 +575,8 @@ static void venc_set_timings(struct omap_dss_device *dssdev,
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
/* turn the venc off and on to get new timings to use */
- venc_disable_display(dssdev);
- venc_enable_display(dssdev);
+ venc_panel_disable(dssdev);
+ venc_panel_enable(dssdev);
}
}
@@ -716,30 +625,79 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
return 0;
}
-static enum omap_dss_update_mode venc_display_get_update_mode(
- struct omap_dss_device *dssdev)
+static struct omap_dss_driver venc_driver = {
+ .probe = venc_panel_probe,
+ .remove = venc_panel_remove,
+
+ .enable = venc_panel_enable,
+ .disable = venc_panel_disable,
+ .suspend = venc_panel_suspend,
+ .resume = venc_panel_resume,
+
+ .get_resolution = omapdss_default_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .set_update_mode = venc_set_update_mode,
+ .get_update_mode = venc_get_update_mode,
+
+ .get_timings = venc_get_timings,
+ .set_timings = venc_set_timings,
+ .check_timings = venc_check_timings,
+
+ .get_wss = venc_get_wss,
+ .set_wss = venc_set_wss,
+
+ .driver = {
+ .name = "venc",
+ .owner = THIS_MODULE,
+ },
+};
+/* driver end */
+
+
+
+int venc_init(struct platform_device *pdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- return OMAP_DSS_UPDATE_AUTO;
- else
- return OMAP_DSS_UPDATE_DISABLED;
+ u8 rev_id;
+
+ mutex_init(&venc.venc_lock);
+
+ venc.wss_data = 0;
+
+ venc.base = ioremap(VENC_BASE, SZ_1K);
+ if (!venc.base) {
+ DSSERR("can't ioremap VENC\n");
+ return -ENOMEM;
+ }
+
+ venc.vdda_dac_reg = dss_get_vdda_dac();
+ if (IS_ERR(venc.vdda_dac_reg)) {
+ iounmap(venc.base);
+ DSSERR("can't get VDDA_DAC regulator\n");
+ return PTR_ERR(venc.vdda_dac_reg);
+ }
+
+ venc_enable_clocks(1);
+
+ rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+ printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
+
+ venc_enable_clocks(0);
+
+ return omap_dss_register_driver(&venc_driver);
+}
+
+void venc_exit(void)
+{
+ omap_dss_unregister_driver(&venc_driver);
+
+ iounmap(venc.base);
}
int venc_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- dssdev->enable = venc_enable_display;
- dssdev->disable = venc_disable_display;
- dssdev->suspend = venc_display_suspend;
- dssdev->resume = venc_display_resume;
- dssdev->get_timings = venc_get_timings;
- dssdev->set_timings = venc_set_timings;
- dssdev->check_timings = venc_check_timings;
- dssdev->get_wss = venc_get_wss;
- dssdev->set_wss = venc_set_wss;
- dssdev->get_update_mode = venc_display_get_update_mode;
-
return 0;
}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index bb694cc52a50..43496d6c377f 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -16,16 +16,7 @@ config FB_OMAP2_DEBUG_SUPPORT
depends on FB_OMAP2
help
Support for debug output. You have to enable the actual printing
- with debug module parameter.
-
-config FB_OMAP2_FORCE_AUTO_UPDATE
- bool "Force main display to automatic update mode"
- depends on FB_OMAP2
- help
- Forces main display to automatic update mode (if possible),
- and also enables tearsync (if possible). By default
- displays that support manual update are started in manual
- update mode.
+ with 'debug' module parameter.
config FB_OMAP2_NUM_FBS
int "Number of framebuffers"
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 4c4bafdfaa43..1ffa760b8545 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -167,12 +167,12 @@ static int omapfb_update_window_nolock(struct fb_info *fbi,
if (w == 0 || h == 0)
return 0;
- display->get_resolution(display, &dw, &dh);
+ display->driver->get_resolution(display, &dw, &dh);
if (x + w > dw || y + h > dh)
return -EINVAL;
- return display->update(display, x, y, w, h);
+ return display->driver->update(display, x, y, w, h);
}
/* This function is exported for SGX driver use */
@@ -202,7 +202,7 @@ static int omapfb_set_update_mode(struct fb_info *fbi,
enum omap_dss_update_mode um;
int r;
- if (!display || !display->set_update_mode)
+ if (!display || !display->driver->set_update_mode)
return -EINVAL;
switch (mode) {
@@ -222,7 +222,7 @@ static int omapfb_set_update_mode(struct fb_info *fbi,
return -EINVAL;
}
- r = display->set_update_mode(display, um);
+ r = display->driver->set_update_mode(display, um);
return r;
}
@@ -233,10 +233,15 @@ static int omapfb_get_update_mode(struct fb_info *fbi,
struct omap_dss_device *display = fb2display(fbi);
enum omap_dss_update_mode m;
- if (!display || !display->get_update_mode)
+ if (!display)
return -EINVAL;
- m = display->get_update_mode(display);
+ if (!display->driver->get_update_mode) {
+ *mode = OMAPFB_AUTO_UPDATE;
+ return 0;
+ }
+
+ m = display->driver->get_update_mode(display);
switch (m) {
case OMAP_DSS_UPDATE_DISABLED:
@@ -374,7 +379,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
void *buf;
int r;
- if (!display || !display->memory_read)
+ if (!display || !display->driver->memory_read)
return -ENOENT;
if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
@@ -389,7 +394,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
return -ENOMEM;
}
- r = display->memory_read(display, buf, mr->buffer_size,
+ r = display->driver->memory_read(display, buf, mr->buffer_size,
mr->x, mr->y, mr->w, mr->h);
if (r > 0) {
@@ -483,6 +488,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_memory_read memory_read;
struct omapfb_vram_info vram_info;
struct omapfb_tearsync_info tearsync_info;
+ struct omapfb_display_info display_info;
} p;
int r = 0;
@@ -490,18 +496,18 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
switch (cmd) {
case OMAPFB_SYNC_GFX:
DBG("ioctl SYNC_GFX\n");
- if (!display || !display->sync) {
+ if (!display || !display->driver->sync) {
/* DSS1 never returns an error here, so we neither */
/*r = -EINVAL;*/
break;
}
- r = display->sync(display);
+ r = display->driver->sync(display);
break;
case OMAPFB_UPDATE_WINDOW_OLD:
DBG("ioctl UPDATE_WINDOW_OLD\n");
- if (!display || !display->update) {
+ if (!display || !display->driver->update) {
r = -EINVAL;
break;
}
@@ -519,7 +525,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case OMAPFB_UPDATE_WINDOW:
DBG("ioctl UPDATE_WINDOW\n");
- if (!display || !display->update) {
+ if (!display || !display->driver->update) {
r = -EINVAL;
break;
}
@@ -648,7 +654,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- r = display->wait_vsync(display);
+ r = display->manager->wait_for_vsync(display->manager);
break;
case OMAPFB_WAITFORGO:
@@ -669,12 +675,12 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
}
- if (!display || !display->run_test) {
+ if (!display || !display->driver->run_test) {
r = -EINVAL;
break;
}
- r = display->run_test(display, p.test_num);
+ r = display->driver->run_test(display, p.test_num);
break;
@@ -684,12 +690,12 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
}
- if (!display || !display->run_test) {
+ if (!display || !display->driver->run_test) {
r = -EINVAL;
break;
}
- r = display->run_test(display, p.test_num);
+ r = display->driver->run_test(display, p.test_num);
break;
@@ -731,13 +737,37 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (!display->enable_te) {
+ if (!display->driver->enable_te) {
r = -ENODEV;
break;
}
- r = display->enable_te(display, !!p.tearsync_info.enabled);
+ r = display->driver->enable_te(display,
+ !!p.tearsync_info.enabled);
+
+ break;
+ }
+
+ case OMAPFB_GET_DISPLAY_INFO: {
+ u16 xres, yres;
+ DBG("ioctl GET_DISPLAY_INFO\n");
+
+ if (display == NULL) {
+ r = -ENODEV;
+ break;
+ }
+
+ display->driver->get_resolution(display, &xres, &yres);
+
+ p.display_info.xres = xres;
+ p.display_info.yres = yres;
+ p.display_info.width = 0;
+ p.display_info.height = 0;
+
+ if (copy_to_user((void __user *)arg, &p.display_info,
+ sizeof(p.display_info)))
+ r = -EFAULT;
break;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index d17caef6915a..4a76917b7cc8 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -54,6 +54,8 @@ module_param_named(test, omapfb_test_pattern, bool, 0644);
#endif
static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
+static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
+ struct omap_dss_device *dssdev);
#ifdef DEBUG
static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
@@ -152,9 +154,9 @@ static void fill_fb(struct fb_info *fbi)
}
#endif
-static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
+static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
{
- struct vrfb *vrfb = &ofbi->region.vrfb;
+ const struct vrfb *vrfb = &ofbi->region.vrfb;
unsigned offset;
switch (rot) {
@@ -179,7 +181,7 @@ static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
return offset;
}
-static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
+static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
return ofbi->region.vrfb.paddr[rot]
@@ -189,7 +191,7 @@ static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
}
}
-static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
+static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.paddr[0];
@@ -197,7 +199,7 @@ static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
return ofbi->region.paddr;
}
-static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
+static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.vaddr[0];
@@ -703,9 +705,9 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
var->width = -1;
var->grayscale = 0;
- if (display && display->get_timings) {
+ if (display && display->driver->get_timings) {
struct omap_video_timings timings;
- display->get_timings(display, &timings);
+ display->driver->get_timings(display, &timings);
/* pixclock in ps, the rest in pixclock */
var->pixclock = timings.pixel_clock != 0 ?
@@ -778,8 +780,8 @@ static int omapfb_release(struct fb_info *fbi, int user)
return 0;
}
-static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix, int rotation)
+static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
+ const struct fb_fix_screeninfo *fix, int rotation)
{
unsigned offset;
@@ -789,8 +791,8 @@ static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
return offset;
}
-static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix, int rotation)
+static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
+ const struct fb_fix_screeninfo *fix, int rotation)
{
unsigned offset;
@@ -1221,11 +1223,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
goto exit;
- if (display->resume)
- r = display->resume(display);
+ if (display->driver->resume)
+ r = display->driver->resume(display);
- if (r == 0 && display->get_update_mode &&
- display->get_update_mode(display) ==
+ if (r == 0 && display->driver->get_update_mode &&
+ display->driver->get_update_mode(display) ==
OMAP_DSS_UPDATE_MANUAL)
do_update = 1;
@@ -1240,8 +1242,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
goto exit;
- if (display->suspend)
- r = display->suspend(display);
+ if (display->driver->suspend)
+ r = display->driver->suspend(display);
break;
@@ -1252,11 +1254,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
exit:
omapfb_unlock(fbdev);
- if (r == 0 && do_update && display->update) {
+ if (r == 0 && do_update && display->driver->update) {
u16 w, h;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
- r = display->update(display, 0, 0, w, h);
+ r = display->driver->update(display, 0, 0, w, h);
}
return r;
@@ -1404,6 +1406,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
unsigned long paddr)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display;
int bytespp;
@@ -1412,7 +1415,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
if (!display)
return 0;
- switch (display->get_recommended_bpp(display)) {
+ switch (omapfb_get_recommended_bpp(fbdev, display)) {
case 16:
bytespp = 2;
break;
@@ -1427,7 +1430,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
if (!size) {
u16 w, h;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
size = max(omap_vrfb_min_phys_size(w, h, bytespp),
@@ -1636,8 +1639,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
if (old_size == size && old_type == type)
return 0;
- if (display && display->sync)
- display->sync(display);
+ if (display && display->driver->sync)
+ display->driver->sync(display);
omapfb_free_fbmem(fbi);
@@ -1745,7 +1748,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
u16 w, h;
int rotation = (var->rotate + ofbi->rotation[0]) % 4;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
if (rotation == FB_ROTATE_CW ||
rotation == FB_ROTATE_CCW) {
@@ -1760,7 +1763,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
var->yres_virtual = var->yres;
if (!var->bits_per_pixel) {
- switch (display->get_recommended_bpp(display)) {
+ switch (omapfb_get_recommended_bpp(fbdev, display)) {
case 16:
var->bits_per_pixel = 16;
break;
@@ -1828,7 +1831,7 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
for (i = 0; i < fbdev->num_displays; i++) {
if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
- fbdev->displays[i]->disable(fbdev->displays[i]);
+ fbdev->displays[i]->driver->disable(fbdev->displays[i]);
omap_dss_put_device(fbdev->displays[i]);
}
@@ -2011,7 +2014,8 @@ static int omapfb_mode_to_timings(const char *mode_str,
}
}
-static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
+static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
+ struct omap_dss_device *display, char *mode_str)
{
int r;
u8 bpp;
@@ -2021,20 +2025,37 @@ static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
if (r)
return r;
- display->panel.recommended_bpp = bpp;
+ fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
+ fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
+ ++fbdev->num_bpp_overrides;
- if (!display->check_timings || !display->set_timings)
+ if (!display->driver->check_timings || !display->driver->set_timings)
return -EINVAL;
- r = display->check_timings(display, &timings);
+ r = display->driver->check_timings(display, &timings);
if (r)
return r;
- display->set_timings(display, &timings);
+ display->driver->set_timings(display, &timings);
return 0;
}
+static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
+ struct omap_dss_device *dssdev)
+{
+ int i;
+
+ BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
+
+ for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
+ if (dssdev == fbdev->bpp_overrides[i].dssdev)
+ return fbdev->bpp_overrides[i].bpp;
+ }
+
+ return dssdev->driver->get_recommended_bpp(dssdev);
+}
+
static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
{
char *str, *options, *this_opt;
@@ -2073,7 +2094,7 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
break;
}
- r = omapfb_set_def_mode(display, mode_str);
+ r = omapfb_set_def_mode(fbdev, display, mode_str);
if (r)
break;
}
@@ -2111,18 +2132,23 @@ static int omapfb_probe(struct platform_device *pdev)
fbdev->dev = &pdev->dev;
platform_set_drvdata(pdev, fbdev);
+ r = 0;
fbdev->num_displays = 0;
dssdev = NULL;
for_each_dss_dev(dssdev) {
omap_dss_get_device(dssdev);
+
if (!dssdev->driver) {
dev_err(&pdev->dev, "no driver for display\n");
- r = -EINVAL;
- goto cleanup;
+ r = -ENODEV;
}
+
fbdev->displays[fbdev->num_displays++] = dssdev;
}
+ if (r)
+ goto cleanup;
+
if (fbdev->num_displays == 0) {
dev_err(&pdev->dev, "no displays\n");
r = -EINVAL;
@@ -2167,35 +2193,28 @@ static int omapfb_probe(struct platform_device *pdev)
}
if (def_display) {
-#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- u16 w, h;
-#endif
- r = def_display->enable(def_display);
- if (r)
+ struct omap_dss_driver *dssdrv = def_display->driver;
+
+ r = def_display->driver->enable(def_display);
+ if (r) {
dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
def_display->name);
+ goto cleanup;
+ }
- /* set the update mode */
if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- if (def_display->enable_te)
- def_display->enable_te(def_display, 1);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
-#else /* MANUAL_UPDATE */
- if (def_display->enable_te)
- def_display->enable_te(def_display, 0);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ u16 w, h;
+ if (dssdrv->enable_te)
+ dssdrv->enable_te(def_display, 1);
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_MANUAL);
- def_display->get_resolution(def_display, &w, &h);
- def_display->update(def_display, 0, 0, w, h);
-#endif
+ dssdrv->get_resolution(def_display, &w, &h);
+ def_display->driver->update(def_display, 0, 0, w, h);
} else {
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_AUTO);
}
}
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index f7c9c739e5ef..cd54fdbfd8bb 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -83,6 +83,12 @@ struct omapfb2_device {
struct omap_overlay *overlays[10];
unsigned num_managers;
struct omap_overlay_manager *managers[10];
+
+ unsigned num_bpp_overrides;
+ struct {
+ struct omap_dss_device *dssdev;
+ u8 bpp;
+ } bpp_overrides[10];
};
struct omapfb_colormode {
@@ -105,6 +111,9 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
+int omapfb_update_window(struct fb_info *fbi,
+ u32 x, u32 y, u32 w, u32 h);
+
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 53f8f1100e81..f9975100d56d 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -831,7 +831,7 @@ static int __devinit pvr2fb_common_init(void)
printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
- fb_info->fix.id, pgprot_val(PAGE_SHARED));
+ fb_info->fix.id, PAGE_SHARED);
printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
fb_info->node, pvr2fb_map);
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a69830d26f7f..8d7653e56df5 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -19,6 +19,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
+#include <linux/ioctl.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/atomic.h>
@@ -106,6 +107,7 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
#define LDRCNTR_SRC 0x00010000
#define LDRCNTR_MRS 0x00000002
#define LDRCNTR_MRC 0x00000001
+#define LDSR_MRS 0x00000100
struct sh_mobile_lcdc_priv;
struct sh_mobile_lcdc_chan {
@@ -122,8 +124,8 @@ struct sh_mobile_lcdc_chan {
struct scatterlist *sglist;
unsigned long frame_end;
unsigned long pan_offset;
- unsigned long new_pan_offset;
wait_queue_head_t frame_end_wait;
+ struct completion vsync_completion;
};
struct sh_mobile_lcdc_priv {
@@ -366,19 +368,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
}
/* VSYNC End */
- if (ldintr & LDINTR_VES) {
- unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR);
- /* Set the source address for the next refresh */
- lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle +
- ch->new_pan_offset);
- if (lcdc_chan_is_sublcd(ch))
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_SRS);
- else
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_MRS);
- ch->pan_offset = ch->new_pan_offset;
- }
+ if (ldintr & LDINTR_VES)
+ complete(&ch->vsync_completion);
}
return IRQ_HANDLED;
@@ -767,25 +758,69 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ struct sh_mobile_lcdc_priv *priv = ch->lcdc;
+ unsigned long ldrcntr;
+ unsigned long new_pan_offset;
+
+ new_pan_offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (info->var.bits_per_pixel / 8));
- if (info->var.xoffset == var->xoffset &&
- info->var.yoffset == var->yoffset)
+ if (new_pan_offset == ch->pan_offset)
return 0; /* No change, do nothing */
- ch->new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * (info->var.bits_per_pixel / 8));
+ ldrcntr = lcdc_read(priv, _LDRCNTR);
- if (ch->new_pan_offset != ch->pan_offset) {
- unsigned long ldintr;
- ldintr = lcdc_read(ch->lcdc, _LDINTR);
- ldintr |= LDINTR_VEE;
- lcdc_write(ch->lcdc, _LDINTR, ldintr);
- sh_mobile_lcdc_deferred_io_touch(info);
- }
+ /* Set the source address for the next refresh */
+ lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset);
+ if (lcdc_chan_is_sublcd(ch))
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
+ else
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
+
+ ch->pan_offset = new_pan_offset;
+
+ sh_mobile_lcdc_deferred_io_touch(info);
+
+ return 0;
+}
+
+static int sh_mobile_wait_for_vsync(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ unsigned long ldintr;
+ int ret;
+
+ /* Enable VSync End interrupt */
+ ldintr = lcdc_read(ch->lcdc, _LDINTR);
+ ldintr |= LDINTR_VEE;
+ lcdc_write(ch->lcdc, _LDINTR, ldintr);
+
+ ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
+ msecs_to_jiffies(100));
+ if (!ret)
+ return -ETIMEDOUT;
return 0;
}
+static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int retval;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ retval = sh_mobile_wait_for_vsync(info);
+ break;
+
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+ return retval;
+}
+
+
static struct fb_ops sh_mobile_lcdc_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = sh_mobile_lcdc_setcolreg,
@@ -795,6 +830,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_copyarea = sh_mobile_lcdc_copyarea,
.fb_imageblit = sh_mobile_lcdc_imageblit,
.fb_pan_display = sh_mobile_fb_pan_display,
+ .fb_ioctl = sh_mobile_ioctl,
};
static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
@@ -962,8 +998,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
init_waitqueue_head(&priv->ch[i].frame_end_wait);
+ init_completion(&priv->ch[i].vsync_completion);
priv->ch[j].pan_offset = 0;
- priv->ch[j].new_pan_offset = 0;
switch (pdata->ch[i].chan) {
case LCDC_CHAN_MAINLCD:
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
index 18b950706cad..4cd50497264d 100644
--- a/drivers/video/sunxvr500.c
+++ b/drivers/video/sunxvr500.c
@@ -400,6 +400,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
static struct pci_device_id e3d_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
+ { PCI_DEVICE(0x1091, 0x7a0), },
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), },
{ .vendor = PCI_VENDOR_ID_3DLABS,
.device = PCI_ANY_ID,
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 4bb9a0b18950..6b52bf65f0b5 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -69,7 +69,7 @@
#ifdef CONFIG_MAC
/* We don't yet have functions to read the PRAM... perhaps we can
adapt them from the PPC code? */
-static int default_vmode = VMODE_640_480_67;
+static int default_vmode = VMODE_CHOOSE;
static int default_cmode = CMODE_8;
#else
static int default_vmode = VMODE_NVRAM;
@@ -326,11 +326,11 @@ int __init valkyriefb_init(void)
#ifdef CONFIG_MAC
if (!MACH_IS_MAC)
- return 0;
+ return -ENODEV;
if (!(mac_bi_data.id == MAC_MODEL_Q630
/* I'm not sure about this one */
|| mac_bi_data.id == MAC_MODEL_P588))
- return 0;
+ return -ENODEV;
/* Hardcoded addresses... welcome to 68k Macintosh country :-) */
frame_buffer_phys = 0xf9000000;
diff --git a/drivers/video/valkyriefb.h b/drivers/video/valkyriefb.h
index 97aaf7bb6417..d787441e5a42 100644
--- a/drivers/video/valkyriefb.h
+++ b/drivers/video/valkyriefb.h
@@ -134,15 +134,7 @@ static struct valkyrie_regvals valkyrie_reg_init_14 = {
{ 1024, 0 },
1024, 768
};
-
-/* Register values for 800x600, 72Hz mode (11) */
-static struct valkyrie_regvals valkyrie_reg_init_11 = {
- 13,
- { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
- { 800, 0 },
- 800, 600
-};
-#endif /* CONFIG_MAC */
+#endif /* !defined CONFIG_MAC */
/* Register values for 832x624, 75Hz mode (13) */
static struct valkyrie_regvals valkyrie_reg_init_13 = {
@@ -152,6 +144,14 @@ static struct valkyrie_regvals valkyrie_reg_init_13 = {
832, 624
};
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+ 13,
+ { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
+ { 800, 0 },
+ 800, 600
+};
+
/* Register values for 800x600, 60Hz mode (10) */
static struct valkyrie_regvals valkyrie_reg_init_10 = {
12,
@@ -188,24 +188,13 @@ static struct valkyrie_regvals *valkyrie_reg_init[VMODE_MAX] = {
NULL,
NULL,
&valkyrie_reg_init_10,
-#ifdef CONFIG_MAC
- NULL,
- NULL,
- &valkyrie_reg_init_13,
- NULL,
- NULL,
- NULL,
- NULL,
-#else
&valkyrie_reg_init_11,
NULL,
&valkyrie_reg_init_13,
+#ifndef CONFIG_MAC
&valkyrie_reg_init_14,
&valkyrie_reg_init_15,
NULL,
&valkyrie_reg_init_17,
#endif
- NULL,
- NULL,
- NULL
};