Subject: [E3-hacking] [PATCH 2/3] Add LCD support for Amstrad Delta

From: Jonathan McDowell <[email-masked]>
Date: Sun, 2 Apr 2006 17:38:32 +0100

Add support for the Amstrad Delta LCD, which is a 12 bit DSTN panel.
This patch treats it as a 16 bit panel; in reality it's in 0444 mode and
will ignore the top 4 bits, but the next patch adds support for that in
the OMAP FB driver.

Signed-Off-By: Jonathan McDowell <[email-masked]>

diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/arch/arm/mach-omap1/board-ams-delta.c linux-omap-lcd/arch/arm/mach-omap1/board-ams-delta.c
--- linux-omap/arch/arm/mach-omap1/board-ams-delta.c	2006-04-02 16:05:20.366858000 +0100
+++ linux-omap-lcd/arch/arm/mach-omap1/board-ams-delta.c	2006-04-02 16:55:12.329102250 +0100
@@ -76,11 +76,16 @@ static struct map_desc ams_delta_io_desc
 	}
 };
 
+static struct omap_lcd_config ams_delta_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
 static struct omap_uart_config ams_delta_uart_config __initdata = {
 	.enabled_uarts = 1,
 };
 
 static struct omap_board_config_kernel ams_delta_config[] = {
+	{ OMAP_TAG_LCD,		&ams_delta_lcd_config },
 	{ OMAP_TAG_UART,	&ams_delta_uart_config },
 };
 
@@ -89,8 +94,14 @@ static struct platform_device ams_delta_
 	.id	= -1,
 };
 
+static struct platform_device ams_delta_lcd_device = {
+	.name	= "lcd_ams_delta",
+	.id	= "-1",
+};
+
 static struct platform_device *ams_delta_devices[] __initdata = {
 	&ams_delta_bl_device,
+	&ams_delta_lcd_device,
 };
 
 static void __init ams_delta_init(void)
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/arch/arm/mach-omap1/clock.c linux-omap-lcd/arch/arm/mach-omap1/clock.c
--- linux-omap/arch/arm/mach-omap1/clock.c	2006-04-02 15:46:08.788044000 +0100
+++ linux-omap-lcd/arch/arm/mach-omap1/clock.c	2006-04-02 16:55:59.588055750 +0100
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 
 #include <asm/io.h>
+#include <asm/mach-types.h>
 
 #include <asm/arch/usb.h>
 #include <asm/arch/clock.h>
@@ -766,6 +767,14 @@ int __init omap1_clk_init(void)
 	omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
 #endif
 
+#ifdef CONFIG_MACH_AMS_DELTA
+	/* Amstrad Delta wants BCLK high when inactive */
+	if (machine_is_ams_delta())
+		omap_writel(omap_readl(ULPD_CLOCK_CTRL) |
+				(1 << SDW_MCLK_INV_BIT),
+				ULPD_CLOCK_CTRL);
+#endif
+
 	/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
 	omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
 
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/arch/arm/mach-omap1/clock.h linux-omap-lcd/arch/arm/mach-omap1/clock.h
--- linux-omap/arch/arm/mach-omap1/clock.h	2006-04-02 15:46:51.617298000 +0100
+++ linux-omap-lcd/arch/arm/mach-omap1/clock.h	2006-04-02 16:56:13.808944500 +0100
@@ -89,6 +89,7 @@ struct arm_idlect1_clk {
 #define EN_DSPTIMCK	5
 
 /* Various register defines for clock controls scattered around OMAP chip */
+#define SDW_MCLK_INV_BIT	2	/* In ULPD_CLKC_CTRL */
 #define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
 #define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
 #define SWD_ULPD_PLL_CLK_REQ	1	/* In SWD_CLK_DIV_CTRL_SEL */
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/drivers/video/omap/lcd_ams_delta.c linux-omap-lcd/drivers/video/omap/lcd_ams_delta.c
--- linux-omap/drivers/video/omap/lcd_ams_delta.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-omap-lcd/drivers/video/omap/lcd_ams_delta.c	2006-04-02 16:53:09.881449750 +0100
@@ -0,0 +1,148 @@
+/*
+ * File: drivers/video/omap/lcd_ams_delta.c
+ *
+ * Based on drivers/video/omap/lcd_inn1510.c
+ *
+ * LCD panel support for the Amstrad E3 (Delta) videophone.
+ *
+ * Copyright (C) 2006 Jonathan McDowell <[email-masked]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#include <asm/arch/board-ams-delta.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+static int ams_delta_panel_init(struct omapfb_device *fbdev)
+{
+	DBGENTER(1);
+	DBGLEAVE(1);
+	return 0;
+}
+
+static void ams_delta_panel_cleanup(void)
+{
+	DBGENTER(1);
+	DBGLEAVE(1);
+}
+
+static int ams_delta_panel_enable(void)
+{
+	DBGENTER(1);
+
+	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
+			AMS_DELTA_LATCH2_LCD_NDISP);
+
+	DBGLEAVE(1);
+	return 0;
+}
+
+static void ams_delta_panel_disable(void)
+{
+	DBGENTER(1);
+
+	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+
+	DBGLEAVE(1);
+}
+
+static unsigned long ams_delta_panel_get_caps(void)
+{
+	return 0;
+}
+
+struct lcd_panel ams_delta_panel = {
+	.name		= "ams-delta",
+	.config		= 0,
+
+	.bpp		= 16,
+	.data_lines	= 16,
+	.x_res		= 480,
+	.y_res		= 320,
+	.pixel_clock	= 4687,
+	.hsw		= 3,
+	.hfp		= 1,
+	.hbp		= 1,
+	.vsw		= 1,
+	.vfp		= 0,
+	.vbp		= 0,
+	.pcd		= 0,
+	.acb		= 37,
+
+	.init		= ams_delta_panel_init,
+	.cleanup	= ams_delta_panel_cleanup,
+	.enable		= ams_delta_panel_enable,
+	.disable	= ams_delta_panel_disable,
+	.get_caps	= ams_delta_panel_get_caps,
+};
+
+static int ams_delta_panel_probe(struct platform_device *pdev)
+{
+	DBGENTER(1);
+	omapfb_register_panel(&ams_delta_panel);
+	return 0;
+}
+
+static int ams_delta_panel_remove(struct platform_device *pdev)
+{
+	DBGENTER(1);
+	return 0;
+}
+
+static int ams_delta_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	DBGENTER(1);
+	return 0;
+}
+
+static int ams_delta_panel_resume(struct platform_device *pdev)
+{
+	DBGENTER(1);
+	return 0;
+}
+
+struct platform_driver ams_delta_panel_driver = {
+	.probe		= ams_delta_panel_probe,
+	.remove		= ams_delta_panel_remove,
+	.suspend	= ams_delta_panel_suspend,
+	.resume		= ams_delta_panel_resume,
+	.driver		= {
+		.name	= "lcd_ams_delta",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int ams_delta_panel_drv_init(void)
+{
+	return platform_driver_register(&ams_delta_panel_driver);
+}
+
+static void ams_delta_panel_drv_cleanup(void)
+{
+	platform_driver_unregister(&ams_delta_panel_driver);
+}
+
+module_init(ams_delta_panel_drv_init);
+module_exit(ams_delta_panel_drv_cleanup);
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/drivers/video/omap/lcdc.c linux-omap-lcd/drivers/video/omap/lcdc.c
--- linux-omap/drivers/video/omap/lcdc.c	2006-04-02 15:53:36.433153500 +0100
+++ linux-omap-lcd/drivers/video/omap/lcdc.c	2006-04-02 16:56:46.278973750 +0100
@@ -836,6 +836,8 @@ static int omap_lcdc_init(struct omapfb_
 	rate = clk_get_rate(tc_ck);
 	clk_put(tc_ck);
 
+	if (machine_is_ams_delta())
+		rate /= 4;
 	if (machine_is_omap_h3())
 		rate /= 3;
 	r = clk_set_rate(omap_lcdc.lcd_ck, rate);
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap/drivers/video/omap/Makefile linux-omap-lcd/drivers/video/omap/Makefile
--- linux-omap/drivers/video/omap/Makefile	2006-04-02 15:53:29.504720500 +0100
+++ linux-omap-lcd/drivers/video/omap/Makefile	2006-04-02 17:03:10.811820750 +0100
@@ -14,6 +14,7 @@ objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMA
 
 objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
 
+objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
 objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
 objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
 objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o

---

From: Jonathan McDowell <[email-masked]>
Date: Sun, 2 Apr 2006 17:36:14 +0100

This patch adds support for the Amstrad Delta LCD backlight. It's the
first patch in a series of 3 enabling full LCD support for the Delta and
is the least intrusive, allowing control of the backlight through the
existing backlight class infrastructure.

diff --git a/arch/arm/configs/ams_delta_defconfig b/arch/arm/configs/ams_delta_defconfig
index 03f02dd..7cc0727 100644
--- a/arch/arm/configs/ams_delta_defconfig
+++ b/arch/arm/configs/ams_delta_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.16-omap1
-# Wed Mar 22 10:53:48 2006
+# Sun Apr  2 16:00:11 2006
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -623,13 +623,44 @@ CONFIG_I2C_OMAP=y
 #
 # Graphics support
 #
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_LPH8923 is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_AMS_DELTA=y
 
 #
 # Sound
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 6178f04..7475587 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -84,6 +84,15 @@ static struct omap_board_config_kernel a
 	{ OMAP_TAG_UART,	&ams_delta_uart_config },
 };
 
+static struct platform_device ams_delta_bl_device = {
+	.name	= "ams-delta-bl",
+	.id	= -1,
+};
+
+static struct platform_device *ams_delta_devices[] __initdata = {
+	&ams_delta_bl_device,
+};
+
 static void __init ams_delta_init(void)
 {
 	iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
@@ -94,6 +103,8 @@ static void __init ams_delta_init(void)
 
 	/* Clear latch2 (NAND, LCD, modem enable) */
 	ams_delta_latch2_write(~0, 0);
+
+	platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
 }
 
 static void __init ams_delta_map_io(void)
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 9d996f2..5f02b00 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -42,6 +42,14 @@ config LCD_DEVICE
 	depends on LCD_CLASS_DEVICE
 	default y
 
+config BACKLIGHT_AMS_DELTA
+	tristate "Amstrad Delta (E3) backlight driver"
+	depends on BACKLIGHT_DEVICE && MACH_AMS_DELTA
+	default y
+	help
+	  If you have an Amstrad Delta (E3) videophone, say y to enable
+	  the backlight driver.
+
 config BACKLIGHT_CORGI
 	tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)"
 	depends on BACKLIGHT_DEVICE && PXA_SHARPSL
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 744210c..2a793ea 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,6 +1,7 @@
 # Backlight & LCD drivers
 
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
+obj-$(CONFIG_BACKLIGHT_AMS_DELTA) += ams_delta_bl.o
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
diff --git a/drivers/video/backlight/ams_delta_bl.c b/drivers/video/backlight/ams_delta_bl.c
new file mode 100644
index 0000000..6b84744
--- /dev/null
+++ b/drivers/video/backlight/ams_delta_bl.c
@@ -0,0 +1,172 @@
+/*
+ * Backlight driver for Amstrad E3 (Delta) videophone.
+ *
+ * Copyright (C) 2006 Jonathan McDowell <[email-masked]>
+ *
+ * Based on Richard Purdie's Corgi driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/omap16xx.h>
+#include <asm/arch/board-ams-delta.h>
+
+#define AMS_DELTA_DEFAULT_INTENSITY	112
+#define AMS_DELTA_MAX_INTENSITY		255
+
+static int ams_delta_bl_powermode = FB_BLANK_UNBLANK;
+static int current_intensity = 0;
+
+static void ams_delta_bl_send_intensity(int intensity)
+{
+	if (ams_delta_bl_powermode != FB_BLANK_UNBLANK) {
+		intensity = 0;
+	}
+
+	omap_writeb(intensity, OMAP16XX_PWL_ENABLE);
+}
+
+static void ams_delta_bl_blank(int blank)
+{
+	switch(blank) {
+
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		if (ams_delta_bl_powermode == FB_BLANK_UNBLANK) {
+			ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
+			ams_delta_bl_send_intensity(0);
+			ams_delta_bl_powermode = blank;
+		}
+		break;
+	case FB_BLANK_UNBLANK:
+		if (ams_delta_bl_powermode != FB_BLANK_UNBLANK) {
+			ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
+				AMS_DELTA_LATCH2_LCD_VBLEN);
+			ams_delta_bl_powermode = blank;
+			ams_delta_bl_send_intensity(current_intensity);
+		}
+		break;
+	}
+}
+
+#ifdef CONFIG_PM
+static int ams_delta_bl_suspend(struct platform_device *dev, pm_message_t state)
+{
+	ams_delta_bl_blank(FB_BLANK_POWERDOWN);
+	return 0;
+}
+
+static int ams_delta_bl_resume(struct platform_device *dev)
+{
+	ams_delta_bl_blank(FB_BLANK_UNBLANK);
+	return 0;
+}
+#else
+#define ams_delta_bl_suspend	NULL
+#define ams_delta_bl_resume	NULL
+#endif
+
+
+static int ams_delta_bl_set_power(struct backlight_device *bd, int state)
+{
+	ams_delta_bl_blank(state);
+	return 0;
+}
+
+static int ams_delta_bl_get_power(struct backlight_device *bd)
+{
+	return ams_delta_bl_powermode;
+}
+
+static int ams_delta_bl_set_intensity(struct backlight_device *bd,
+		int intensity)
+{
+	if (intensity > AMS_DELTA_MAX_INTENSITY)
+		intensity = AMS_DELTA_MAX_INTENSITY;
+	ams_delta_bl_send_intensity(intensity);
+	current_intensity = intensity;
+	return 0;
+}
+
+static int ams_delta_bl_get_intensity(struct backlight_device *bd)
+{
+	return current_intensity;
+}
+
+static struct backlight_properties ams_delta_bl_data = {
+	.owner		= THIS_MODULE,
+	.get_power      = ams_delta_bl_get_power,
+	.set_power      = ams_delta_bl_set_power,
+	.max_brightness = AMS_DELTA_MAX_INTENSITY,
+	.get_brightness = ams_delta_bl_get_intensity,
+	.set_brightness = ams_delta_bl_set_intensity,
+};
+
+static struct backlight_device *ams_delta_backlight_device;
+
+static int __init ams_delta_bl_probe(struct platform_device *pdev)
+{
+	ams_delta_backlight_device = backlight_device_register("ams-delta-bl",
+			NULL, &ams_delta_bl_data);
+	if (IS_ERR(ams_delta_backlight_device))
+		return PTR_ERR(ams_delta_backlight_device);
+
+	omap_writeb(1, OMAP16XX_PWL_CLK_ENABLE);
+	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
+			AMS_DELTA_LATCH2_LCD_VBLEN);
+	ams_delta_bl_set_intensity(NULL, AMS_DELTA_DEFAULT_INTENSITY);
+
+	printk("Amstrad Delta backlight driver initialized.\n");
+	return 0;
+}
+
+static int ams_delta_bl_remove(struct platform_device *dev)
+{
+	backlight_device_unregister(ams_delta_backlight_device);
+
+	ams_delta_bl_set_intensity(NULL, 0);
+	omap_writeb(0, OMAP16XX_PWL_CLK_ENABLE);
+	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
+
+	printk("Amstrad Delta backlight driver unloaded\n");
+	return 0;
+}
+
+static struct platform_driver ams_delta_bl_driver = {
+	.probe		= ams_delta_bl_probe,
+	.remove		= ams_delta_bl_remove,
+	.suspend	= ams_delta_bl_suspend,
+	.resume		= ams_delta_bl_resume,
+	.driver		= {
+		.name	= "ams-delta-bl",
+	},
+};
+
+static int __init ams_delta_bl_init(void)
+{
+	return platform_driver_register(&ams_delta_bl_driver);
+}
+
+static void __exit ams_delta_bl_exit(void)
+{
+	platform_driver_unregister(&ams_delta_bl_driver);
+}
+
+module_init(ams_delta_bl_init);
+module_exit(ams_delta_bl_exit);
+
+MODULE_AUTHOR("Jonathan McDowell <[email-masked]>");
+MODULE_DESCRIPTION("Amstrad Delta backlight driver");
+MODULE_LICENSE("GPLv2");

---

From: Jonathan McDowell <[email-masked]>
Date: Sun, 2 Apr 2006 17:41:14 +0100

This patch adds support for an RGB444 mode to the OMAP FB driver; it's
used by the Amstrad Delta which has a 12 bit DSTN screen setup in 444
mode.

Mark Underwood did the original work for this patch:

http://www.earth.li/pipermail/e3-hacking/2006-March/000376.html

I have simply updated to the latest git tree.

diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/drivers/video/omap/lcd_ams_delta.c linux-omap-lcd-444/drivers/video/omap/lcd_ams_delta.c
--- linux-omap-lcd/drivers/video/omap/lcd_ams_delta.c	2006-04-02 16:53:09.881449750 +0100
+++ linux-omap-lcd-444/drivers/video/omap/lcd_ams_delta.c	2006-04-02 17:21:04.654931750 +0100
@@ -77,7 +77,7 @@ struct lcd_panel ams_delta_panel = {
 	.name		= "ams-delta",
 	.config		= 0,
 
-	.bpp		= 16,
+	.bpp		= 12,
 	.data_lines	= 16,
 	.x_res		= 480,
 	.y_res		= 320,
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/drivers/video/omap/lcdc.c linux-omap-lcd-444/drivers/video/omap/lcdc.c
--- linux-omap-lcd/drivers/video/omap/lcdc.c	2006-04-02 16:56:46.278973750 +0100
+++ linux-omap-lcd-444/drivers/video/omap/lcdc.c	2006-04-02 17:21:47.105584750 +0100
@@ -353,6 +353,7 @@ static int omap_lcdc_setup_plane(int pla
 		omap_lcdc.palette_size = 512;
 		break;
 	case OMAPFB_COLOR_RGB565:
+	case OMAPFB_COLOR_RGB444:
 		omap_lcdc.bpp = 16;
 		omap_lcdc.palette_code = 0x4000;
 		omap_lcdc.palette_size = 32;
@@ -720,7 +721,11 @@ static int alloc_fbmem(int req_size)
 	int frame_size;
 	struct lcd_panel *panel = omap_lcdc.fbdev->panel;
 
-	frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+	if (panel->bpp == 12)
+		frame_size = PAGE_ALIGN(panel->x_res * 16 / 8 * panel->y_res);
+	else
+		frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 *
+				panel->y_res);
 	if (req_size > frame_size)
 		frame_size = req_size;
 	omap_lcdc.vram_size = frame_size;
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/drivers/video/omap/omapfb_main.c linux-omap-lcd-444/drivers/video/omap/omapfb_main.c
--- linux-omap-lcd/drivers/video/omap/omapfb_main.c	2006-04-02 15:52:24.524659500 +0100
+++ linux-omap-lcd-444/drivers/video/omap/omapfb_main.c	2006-04-02 17:25:23.947136500 +0100
@@ -239,6 +239,7 @@ static int _setcolreg(struct fb_info *in
 							transp, update_hw_pal);
 		/* Fallthrough */
 	case OMAPFB_COLOR_RGB565:
+	case OMAPFB_COLOR_RGB444:
 		if (r != 0)
 			break;
 
@@ -249,8 +250,14 @@ static int _setcolreg(struct fb_info *in
 
 		if (regno < 16) {
 			u16 pal;
-			pal = ((red >> 11) << 11) | ((green >> 10) << 5) |
-				(blue >> 11);
+			if (fbdev->color_mode == OMAPFB_COLOR_RGB444)
+				pal = ((red >> 12) << 8) |
+					((green >> 12) << 4) |
+					(blue >> 12);
+			else
+				pal = ((red >> 11) << 11) |
+					((green >> 10) << 5) |
+					(blue >> 11);
 			((u32 *)(info->pseudo_palette))[regno] = pal;
 		}
 		break;
@@ -402,12 +409,19 @@ static int set_fb_var(struct omapfb_devi
 	unsigned long	line_size;
 	struct lcd_panel *panel = fbdev->panel;
 
-	bpp = var->bits_per_pixel = panel->bpp;
+	if (panel->bpp == 12)
+		/* 12-bpp mode stores colours in 16 bits and ignores top 4 */
+		bpp = var->bits_per_pixel = 16;
+	else
+		bpp = var->bits_per_pixel = panel->bpp;
 
-	switch (bpp) {
+	switch (panel->bpp) {
 	case 16:
 		fbdev->color_mode = OMAPFB_COLOR_RGB565;
 		break;
+	case 12:
+		fbdev->color_mode = OMAPFB_COLOR_RGB444;
+		break;
 	case 8:
 		fbdev->color_mode = OMAPFB_COLOR_CLUT_8BPP;
 		break;
@@ -453,9 +467,21 @@ static int set_fb_var(struct omapfb_devi
 		var->yoffset = var->yres_virtual - var->yres;
 	line_size = var->xres * bpp / 8;
 
-	var->red.offset	 = 11; var->red.length	 = 5; var->red.msb_right   = 0;
-	var->green.offset= 5;  var->green.length = 6; var->green.msb_right = 0;
-	var->blue.offset = 0;  var->blue.length  = 5; var->blue.msb_right  = 0;
+	if (fbdev->color_mode == OMAPFB_COLOR_RGB444) {
+		var->red.offset	 = 8; var->red.length	= 4;
+		var->red.msb_right   = 0;
+		var->green.offset= 4; var->green.length = 4;
+		var->green.msb_right = 0;
+		var->blue.offset = 0; var->blue.length  = 4;
+		var->blue.msb_right  = 0;
+	} else {
+		var->red.offset	 = 11; var->red.length	 = 5;
+		var->red.msb_right   = 0;
+		var->green.offset= 5;  var->green.length = 6;
+		var->green.msb_right = 0;
+		var->blue.offset = 0;  var->blue.length  = 5;
+		var->blue.msb_right  = 0;
+	}
 
 	var->height		= -1;
 	var->width		= -1;
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/include/asm-arm/arch/omapfb.h linux-omap-lcd-444/include/asm-arm/arch/omapfb.h
--- linux-omap-lcd/include/asm-arm/arch/omapfb.h	2006-04-02 15:51:02.303521000 +0100
+++ linux-omap-lcd-444/include/asm-arm/arch/omapfb.h	2006-04-02 17:20:38.957325750 +0100
@@ -64,6 +64,7 @@ enum omapfb_color_format {
 	OMAPFB_COLOR_CLUT_4BPP,
 	OMAPFB_COLOR_CLUT_2BPP,
 	OMAPFB_COLOR_CLUT_1BPP,
+	OMAPFB_COLOR_RGB444,
 };
 
 struct omapfb_update_window {
diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/include/asm-arm/arch-omap/omapfb.h linux-omap-lcd-444/include/asm-arm/arch-omap/omapfb.h
--- linux-omap-lcd/include/asm-arm/arch-omap/omapfb.h	2006-04-02 15:51:02.303521000 +0100
+++ linux-omap-lcd-444/include/asm-arm/arch-omap/omapfb.h	2006-04-02 17:20:38.957325750 +0100
@@ -64,6 +64,7 @@ enum omapfb_color_format {
 	OMAPFB_COLOR_CLUT_4BPP,
 	OMAPFB_COLOR_CLUT_2BPP,
 	OMAPFB_COLOR_CLUT_1BPP,
+	OMAPFB_COLOR_RGB444,
 };
 
 struct omapfb_update_window {

---

From: Mark Underwood <[email-masked]>
Date: Mon, 3 Apr 2006 21:21:52 +0100 (BST)

I would have liked to have the chance to send this patch in myself as I did the original work.
Jonathan, in future please check with people if they want to post their patch before before doing
it for them. 
 
Back to the patch. It's pretty much the same as my original impart from the _setcolreg part in
which  
I calculated the offsets using the data in the var structure like so (taken from my original
patch):

@@ -290,8 +292,9 @@ static int _setcolreg(struct fb_info *in
 
 		if (regno < 16) {
 			u16 pal;
-			pal = ((red >> 11) << 11) | ((green >> 10) << 5) |
-				(blue >> 11);
+			pal = ((red >> (16 - var->red.length)) << var->red.offset) |
+				((green >> (16 - var->green.length)) << var->green.offset) |
+				(blue >> (16 - var->blue.length));
 			((u32 *)(info->pseudo_palette))[regno] = pal;
 		}
 		break;

This seems a more flexible way of doing it and means that it would be easier to add extra colour
depths which otherwise could end up with lots of "if else's". I'll create a updated patch which
uses the method above and post it.

Mark

--- Jonathan McDowell <[email-masked]> wrote:

> diff -rupN -X linux-omap/Documentation/dontdiff
> linux-omap-lcd/drivers/video/omap/lcd_ams_delta.c
> linux-omap-lcd-444/drivers/video/omap/lcd_ams_delta.c
> diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/drivers/video/omap/lcdc.c
> linux-omap-lcd-444/drivers/video/omap/lcdc.c
> diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/drivers/video/omap/omapfb_main.c
> linux-omap-lcd-444/drivers/video/omap/omapfb_main.c
> diff -rupN -X linux-omap/Documentation/dontdiff linux-omap-lcd/include/asm-arm/arch/omapfb.h
> linux-omap-lcd-444/include/asm-arm/arch/omapfb.h
> diff -rupN -X linux-omap/Documentation/dontdiff
> linux-omap-lcd/include/asm-arm/arch-omap/omapfb.h
> linux-omap-lcd-444/include/asm-arm/arch-omap/omapfb.h
> _______________________________________________
> e3-hacking mailing list
> [email-masked]
> http://www.earth.li/cgi-bin/mailman/listinfo/e3-hacking
> 

___________________________________________________________ 
To help you stay safe and secure online, we've developed the all new Yahoo! Security Centre. http://uk.security.yahoo.com

---

From: Mark Underwood <[email-masked]>
Date: Mon, 3 Apr 2006 21:21:52 +0100 (BST)

if (regno < 16) {
 			u16 pal;

Mark

---

From: Matthew Garrett <[email-masked]>
Date: Tue, 4 Apr 2006 00:41:23 +0100

> Jonathan, in future please check with people if they want to post their patch before before doing

If you wish to have control over your creative works, I'd suggest not 
basing them on GPLed code.
-- 
Matthew Garrett | [email-masked]

---

From: Jasmine Strong <[email-masked]>
Date: Tue, 4 Apr 2006 01:58:08 +0200

> basing them on GPLed code.

Many people seem to forget that there is a difference between legal
compulsion and social courtesy.  While you are right that there was
none of the former, you're forgetting that in a civilized culture we try
to do the right thing even when there's nobody standing behind us
ready to force us.

-J.