From c02b843c2732bc7b15a3e35b5dd715d68225bbd1 Mon Sep 17 00:00:00 2001
From: Imre Deak <imre.deak@nokia.com>
Date: Wed, 8 Apr 2009 12:51:46 +0200
Subject: [PATCH] DSS2: pass the default FB color format through board info

Add a field to the FB memory region platform data, so that board
init code can pass a default color format to the driver. Set this
format as an initial setting for the given FB.

This is needed for an upcoming patch that adds detection of the
color format set by the bootloader.

Signed-off-by: Imre Deak <imre.deak@nokia.com>
---
 drivers/video/omap2/omapfb/omapfb-main.c |  121 +++++++++++++++++++++++++++---
 drivers/video/omap2/omapfb/omapfb.h      |    2 +
 include/linux/omapfb.h                   |    5 +
 3 files changed, 117 insertions(+), 11 deletions(-)

diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 12ce0c3..67c67c2 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -370,6 +370,21 @@ static enum omap_color_mode fb_mode_to_dss_mode(struct fb_var_screeninfo *var)
 	return -EINVAL;
 }
 
+static int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
+			       struct fb_var_screeninfo *var)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
+		struct omapfb_colormode *mode = &omapfb_colormodes[i];
+		if (dssmode == mode->dssmode) {
+			assign_colormode_to_var(var, mode);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
 void set_fb_fix(struct fb_info *fbi)
 {
 	struct fb_fix_screeninfo *fix = &fbi->fix;
@@ -1267,6 +1282,60 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
 	return omapfb_alloc_fbmem(fbi, size, paddr);
 }
 
+static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format format)
+{
+	enum omap_color_mode mode;
+
+	switch (format) {
+	case OMAPFB_COLOR_RGB565:
+		mode = OMAP_DSS_COLOR_RGB16;
+		break;
+	case OMAPFB_COLOR_YUV422:
+		mode = OMAP_DSS_COLOR_YUV2;
+		break;
+	case OMAPFB_COLOR_CLUT_8BPP:
+		mode = OMAP_DSS_COLOR_CLUT8;
+		break;
+	case OMAPFB_COLOR_CLUT_4BPP:
+		mode = OMAP_DSS_COLOR_CLUT4;
+		break;
+	case OMAPFB_COLOR_CLUT_2BPP:
+		mode = OMAP_DSS_COLOR_CLUT2;
+		break;
+	case OMAPFB_COLOR_CLUT_1BPP:
+		mode = OMAP_DSS_COLOR_CLUT1;
+		break;
+	case OMAPFB_COLOR_RGB444:
+		mode = OMAP_DSS_COLOR_RGB12U;
+		break;
+	case OMAPFB_COLOR_YUY422:
+		mode = OMAP_DSS_COLOR_UYVY;
+		break;
+	case OMAPFB_COLOR_ARGB16:
+		mode = OMAP_DSS_COLOR_ARGB16;
+		break;
+	case OMAPFB_COLOR_RGB24U:
+		mode = OMAP_DSS_COLOR_RGB24U;
+		break;
+	case OMAPFB_COLOR_RGB24P:
+		mode = OMAP_DSS_COLOR_RGB24P;
+		break;
+	case OMAPFB_COLOR_ARGB32:
+		mode = OMAP_DSS_COLOR_ARGB32;
+		break;
+	case OMAPFB_COLOR_RGBA32:
+		mode = OMAP_DSS_COLOR_RGBA32;
+		break;
+	case OMAPFB_COLOR_RGBX32:
+		mode = OMAP_DSS_COLOR_RGBX32;
+		break;
+	default:
+		mode = -EINVAL;
+	}
+
+	return mode;
+}
+
 static int omapfb_parse_vram_param(const char *param, int max_entries,
 		unsigned long *sizes, unsigned long *paddrs)
 {
@@ -1483,9 +1552,36 @@ int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 	}
 
 	var->nonstd = 0;
+	var->bits_per_pixel = 0;
 
 	var->rotate = ofbi->rotation;
 
+	/*
+	 * Check if there is a default color format set in the board file,
+	 * and use this format instead the default deducted from the
+	 * display bpp.
+	 */
+	if (fbdev->dev->platform_data) {
+		struct omapfb_platform_data *opd;
+		int id = ofbi->id;
+
+		opd = fbdev->dev->platform_data;
+		if (opd->mem_desc.region[id].format_used) {
+			enum omap_color_mode mode;
+			enum omapfb_color_format format;
+
+			format = opd->mem_desc.region[id].format;
+			mode = fb_format_to_dss_mode(format);
+			if (mode < 0) {
+				r = mode;
+				goto err;
+			}
+			r = dss_mode_to_fb_mode(mode, var);
+			if (r < 0)
+				goto err;
+		}
+	}
+
 	if (display) {
 		u16 w, h;
 		display->get_resolution(display, &w, &h);
@@ -1502,16 +1598,18 @@ int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 		var->xres_virtual = var->xres;
 		var->yres_virtual = var->yres;
 
-		switch (display->get_recommended_bpp(display)) {
-		case 16:
-			var->bits_per_pixel = 16;
-			break;
-		case 24:
-			var->bits_per_pixel = 32;
-			break;
-		default:
-			dev_err(fbdev->dev, "illegal display bpp\n");
-			return -EINVAL;
+		if (!var->bits_per_pixel) {
+			switch (display->get_recommended_bpp(display)) {
+				case 16:
+					var->bits_per_pixel = 16;
+					break;
+				case 24:
+					var->bits_per_pixel = 32;
+					break;
+				default:
+					dev_err(fbdev->dev, "illegal display bpp\n");
+					return -EINVAL;
+			}
 		}
 	} else {
 		/* if there's no display, let's just guess some basic values */
@@ -1519,7 +1617,8 @@ int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 		var->yres = 240;
 		var->xres_virtual = var->xres;
 		var->yres_virtual = var->yres;
-		var->bits_per_pixel = 16;
+		if (!var->bits_per_pixel)
+			var->bits_per_pixel = 16;
 	}
 
 	r = check_fb_var(fbi, var);
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 65e9e6e..2607def 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -27,6 +27,8 @@
 #define DEBUG
 #endif
 
+#include <mach/display.h>
+
 #ifdef DEBUG
 extern unsigned int omapfb_debug;
 #define DBG(format, ...) \
diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
index 96190b2..7a34f22 100644
--- a/include/linux/omapfb.h
+++ b/include/linux/omapfb.h
@@ -298,6 +298,11 @@ struct omapfb_mem_region {
 	void __iomem	*vaddr;
 	unsigned long	size;
 	u8		type;		/* OMAPFB_PLANE_MEM_* */
+	enum omapfb_color_format format;/* OMAPFB_COLOR_* */
+	unsigned	format_used:1;	/* Must be set when format is set.
+					 * Needed b/c of the badly chosen 0
+					 * base for OMAPFB_COLOR_* values
+					 */
 	unsigned	alloc:1;	/* allocated by the driver */
 	unsigned	map:1;		/* kernel mapped by the driver */
 };
-- 
1.5.6.5

