[PATCH 11/23] add new dispaly mode, such as extended mode, dualview, clone mode

Brad Figg brad.figg at canonical.com
Thu Aug 27 23:20:51 UTC 2009


From: Green Wan <gwan at marvell.com>

Signed-off-by: Green Wan <gwan at marvell.com>
Signed-off-by: Saeed Bishara <saeed at marvell.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 drivers/video/marvell/Kconfig       |    8 ++
 drivers/video/marvell/Makefile      |    1 +
 drivers/video/marvell/dovefb_base.c |   32 +++++++++-
 drivers/video/marvell/dovefb_gfx.c  |  123 ++++++++++++++++++++++++++---------
 drivers/video/marvell/dovefb_ovly.c |   59 ++++++++++++++---
 5 files changed, 182 insertions(+), 41 deletions(-)

diff --git a/drivers/video/marvell/Kconfig b/drivers/video/marvell/Kconfig
index a827ee8..c924eb2 100644
--- a/drivers/video/marvell/Kconfig
+++ b/drivers/video/marvell/Kconfig
@@ -118,12 +118,20 @@ config FB_DOVE_CLCD_DEFAULT_OPTION
 	depends on FB_DOVE && (FB_DOVE_CLCD || FB_DOVE_CLCD1)
 	default "lcd0:1280x768-24 at 60,lcd1:1024x768-16 at 60"
 
+config DOVEFB_DISPLAY_MODE
+	tristate "Support display configuration."
+	depends on FB_DOVE && FB_DOVE_CLCD && FB_DOVE_CLCD1
+	default y if ARCH_DOVE
+	---help---
+	Say Y here if you want to build driver into kernel. Default is N.
+
 config FB_DOVE_CLCD_FLAREON_GV
 	tristate "Marvell DOVE Color LCD - Flareon GV"
 	depends on FB_DOVE && (FB_DOVE_CLCD || FB_DOVE_CLCD1)
 	default y if ARCH_REALVIEW
 	---help---
 	Say Y here if your LCD version is on Flareon GV. Default is N.
+
 ## Following is for MUSTANG LCD config
 config FB_MUSTANG_CLCD
     tristate "Marvell Mustang Color LCD support"
diff --git a/drivers/video/marvell/Makefile b/drivers/video/marvell/Makefile
index 0ea1549..2c8ae74 100644
--- a/drivers/video/marvell/Makefile
+++ b/drivers/video/marvell/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_FB_DOVE)          += dovefb_base.o dovefb_gfx.o dovefb_ovly.o dovef
 
 obj-$(CONFIG_FB_DOVE_DCON)     += dovedcon.o
 
+obj-$(CONFIG_DOVEFB_DISPLAY_MODE)	+=	dovefb_display.o
diff --git a/drivers/video/marvell/dovefb_base.c b/drivers/video/marvell/dovefb_base.c
index 39501ab..3e45db5 100644
--- a/drivers/video/marvell/dovefb_base.c
+++ b/drivers/video/marvell/dovefb_base.c
@@ -41,12 +41,19 @@
 
 #include <video/dovefb.h>
 #include <video/dovefbreg.h>
+#include <video/dovefb_display.h>
 #include "dovefb_if.h"
 
 #define MAX_HWC_SIZE		(64*64*2)
 #define DEFAULT_REFRESH		60	/* Hz */
 #define DOVEFB_INT_MASK  DMA_FRAME_IRQ0_ENA(0x1)
 
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+struct display_settings lcd_config;
+EXPORT_SYMBOL(lcd_config);
+#endif
+
 static int dovefb_init_layer(struct platform_device *pdev,
 		enum dovefb_type type, struct dovefb_info *info,
 		struct resource *res);
@@ -533,7 +540,6 @@ bad_options:
 }
 #endif
 
-
 static int dovefb_init_layer(struct platform_device *pdev,
 		enum dovefb_type type, struct dovefb_info *info,
 		struct resource *res)
@@ -599,6 +605,7 @@ static int dovefb_init_layer(struct platform_device *pdev,
 	 * fix me, currently, vpro occupy a very large dma.
 	 * It's better not to alloc DMA buffer from dma_alloc_xxx
 	 */
+//	if (0 == fb_start) {
 #ifdef CONFIG_ARCH_DOVE
 	dfli->fb_start = dma_alloc_writecombine(dfli->dev, dfli->fb_size,
 						&dfli->fb_start_dma,
@@ -619,7 +626,14 @@ static int dovefb_init_layer(struct platform_device *pdev,
 		goto failed;
 	}
 
-	memset(dfli->fb_start, 0, dfli->fb_size);
+//		fb_start = dfli->fb_start;
+//		fb_start_dma = dfli->fb_start_dma;
+//	} else {
+//		dfli->fb_start = fb_start;
+//		dfli->fb_start_dma = fb_start_dma;
+//	}
+
+	//memset(dfli->fb_start, 0, dfli->fb_size);
 	fi->fix.smem_start = dfli->fb_start_dma;
 	fi->fix.smem_len = dfli->fb_size;
 	fi->screen_base = dfli->fb_start;
@@ -839,6 +853,7 @@ static int __init dovefb_probe(struct platform_device *pdev)
 		goto failed_irq;
 	}
 
+
 	ret = register_framebuffer(info->vid_plane->fb_info);
 	if (ret < 0) {
 		printk(KERN_ERR "doveFB: Failed to register VID FB.\n");
@@ -846,6 +861,19 @@ static int __init dovefb_probe(struct platform_device *pdev)
 		goto failed_fb;
 	}
 
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+	lcd_config.display_mode = DISPLAY_NORMAL;
+	lcd_config.extend_ratio = 2;
+
+	if (info->id == 0) {
+		lcd_config.lcd0_gfx = info->gfx_plane->fb_info;
+		lcd_config.lcd0_vid = info->vid_plane->fb_info;
+	} else {
+		lcd_config.lcd1_gfx = info->gfx_plane->fb_info;
+		lcd_config.lcd1_vid = info->vid_plane->fb_info;
+	}
+#endif
 	printk(KERN_INFO "  o dovefb: frame buffer device was successfully "
 			"loaded.\n");
 	return 0;
diff --git a/drivers/video/marvell/dovefb_gfx.c b/drivers/video/marvell/dovefb_gfx.c
index 6229bf5..c829dc7 100755
--- a/drivers/video/marvell/dovefb_gfx.c
+++ b/drivers/video/marvell/dovefb_gfx.c
@@ -42,12 +42,17 @@
 #include "../edid.h"
 #include <video/dovefb.h>
 #include <video/dovefbreg.h>
+#include <video/dovefb_display.h>
 
 #include "dovefb_if.h"
 
 #define MAX_HWC_SIZE		(64*64*2)
 #define DEFAULT_REFRESH		60	/* Hz */
 
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+extern struct display_settings lcd_config;
+#endif
 static int dovefb_fill_edid(struct fb_info *fi,
 				struct dovefb_mach_info *dmi);
 static int wait_for_vsync(struct dovefb_layer_info *dfli);
@@ -242,12 +247,8 @@ static void set_clock_divider(struct dovefb_layer_info *dfli,
 	int needed_pixclk;
 	u64 div_result;
 	u32 x = 0;
-#ifdef CONFIG_DOVE_REV_Z0
+	struct dovefb_info *info = dfli->info;
 	struct dovefb_mach_info *dmi = dfli->dev->platform_data;
-#else
-	u32 axi_div, lcd_div, is_ext;
-#endif
-
 
 	/*
 	 * Notice: The field pixclock is used by linux fb
@@ -274,10 +275,13 @@ static void set_clock_divider(struct dovefb_layer_info *dfli,
 	 * Calc divider according to refresh rate.
 	 */
 	div_result = 1000000000000ll;
+
+	if(info->fixed_output)
+		m = &info->out_vmode;
+
 	do_div(div_result, m->pixclock);
 	needed_pixclk = (u32)div_result;
 
-#ifdef CONFIG_DOVE_REV_Z0
 	divider_int = dmi->sclk_clock / needed_pixclk;
 	/* check whether divisor is too small. */
 	if (divider_int < 2) {
@@ -285,15 +289,10 @@ static void set_clock_divider(struct dovefb_layer_info *dfli,
 				 "Try smaller resolution\n");
 		divider_int = 2;
 	}
-#else
-	calc_best_clock_div(needed_pixclk, &axi_div, &lcd_div, &is_ext);
-	divider_int = lcd_div;
-
-	printk(KERN_INFO "pix_clock = %d, axi_div = %d, lcd_div = %d, is_ext = %d.\n",
-			needed_pixclk, axi_div, lcd_div, is_ext);
 
-	set_external_lcd_clock(axi_div, is_ext);
-#endif /* CONFIG_DOVE_REV_Z0 */
+#ifndef CONFIG_DOVE_REV_Z0
+	set_external_lcd_clock(2, 0);
+#endif /* !CONFIG_DOVE_REV_Z0 */
 
 	/*
 	 * Set setting to reg.
@@ -310,7 +309,8 @@ static void set_dma_control0(struct dovefb_layer_info *dfli)
 	 * Set bit to enable graphics DMA.
 	 */
 	x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0);
-	x |= (dfli->active && dfli->enabled) ? CFG_GRA_ENA_MASK : 0;
+	//x |= (dfli->active && dfli->enabled) ? CFG_GRA_ENA_MASK : 0;
+	x |= CFG_GRA_ENA_MASK;
 	dfli->active = 0;
 
 	/*
@@ -323,6 +323,11 @@ static void set_dma_control0(struct dovefb_layer_info *dfli)
 		x &= ~0x10000000;
 
 	/*
+	 * enable horizontal smooth scaling.
+	 */
+	x |= 0x1 << 14;
+
+	/*
 	 * Cursor enabled?
 	 */
 	if (dfli->cursor_enabled)
@@ -391,10 +396,32 @@ static void set_graphics_start(struct fb_info *fi, int xoffset, int yoffset)
 	int pixel_offset;
 	unsigned long addr;
 
-	pixel_offset = (yoffset * var->xres_virtual) + xoffset;
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+	if (lcd_config.display_mode < 3) {
+		pixel_offset = (yoffset * var->xres_virtual) + xoffset;
+
+		addr = dfli->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+		writel(addr, dfli->reg_base + LCD_CFG_GRA_START_ADDR0);
+		if (lcd_config.display_mode == DISPLAY_DUALVIEW) {
+			struct dovefb_layer_info *dfli1 = lcd_config.lcd1_gfx->par;
+			int pixel_offset1;
+			unsigned long addr1;
+
+
+			pixel_offset1 = (yoffset * var->xres_virtual) + xoffset;
+
+			addr1 = dfli->fb_start_dma + (pixel_offset1 * (var->bits_per_pixel >> 3));
+			writel(addr1, dfli1->reg_base + LCD_CFG_GRA_START_ADDR0);
+
+		}
+	}
+#else
+		pixel_offset = (yoffset * var->xres_virtual) + xoffset;
 
-	addr = dfli->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
-	writel(addr, dfli->reg_base + LCD_CFG_GRA_START_ADDR0);
+		addr = dfli->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+		writel(addr, dfli->reg_base + LCD_CFG_GRA_START_ADDR0);
+#endif
 }
 
 static int dovefb_pan_display(struct fb_var_screeninfo *var,
@@ -486,21 +513,20 @@ static int dovefb_gfx_set_par(struct fb_info *fi)
 		fi->fix.visual = FB_VISUAL_TRUECOLOR;
 	fi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
 
-	/*
-	 * Disable panel output while we setup the display.
-	 */
-	x = readl(dfli->reg_base + LCD_SPU_DUMB_CTRL);
-	writel(x & ~1, dfli->reg_base + LCD_SPU_DUMB_CTRL);
+	x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0);
+	if ((x & CFG_GRA_ENA_MASK))
+		wait_for_vsync(dfli);
 
 	/*
 	 * Configure global panel parameters.
 	 */
-	if (info->fixed_output)
+	if (info->fixed_output) {
 		writel((info->out_vmode.yres << 16) | info->out_vmode.xres,
 			dfli->reg_base + LCD_SPU_V_H_ACTIVE);
-	else
+	} else {
 		writel((var->yres << 16) | var->xres,
 			dfli->reg_base + LCD_SPU_V_H_ACTIVE);
+	}
 
 	/*
 	 * convet var to video mode
@@ -518,18 +544,54 @@ static int dovefb_gfx_set_par(struct fb_info *fi)
 	/*
 	 * Configure graphics DMA parameters.
 	 */
-	set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+	switch (lcd_config.display_mode) {
+	case DISPLAY_EXTENDED:
+		if (1 == dfli->info->id) {
+			set_graphics_start(fi, fi->var.xoffset+(var->xres/2), fi->var.yoffset);
+			break;
+		}
+	case DISPLAY_NORMAL:
+	case DISPLAY_CLONE:
+	case DISPLAY_DUALVIEW:
+		set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
+		break;
+	default:
+		;
+	}
+#else
+		set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
+#endif
 	x = readl(dfli->reg_base + LCD_CFG_GRA_PITCH);
 	x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
 	writel(x, dfli->reg_base + LCD_CFG_GRA_PITCH);
-	writel((var->yres << 16) | var->xres,
+
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+	switch (lcd_config.display_mode) {
+	case DISPLAY_EXTENDED:
+		writel((var->yres << 16) | (var->xres*lcd_config.extend_ratio/4),
+				dfli->reg_base + LCD_SPU_GRA_HPXL_VLN);
+		break;
+	case DISPLAY_NORMAL:
+	case DISPLAY_CLONE:
+	case DISPLAY_DUALVIEW:
+		writel((var->yres << 16) | (var->xres),
 			dfli->reg_base + LCD_SPU_GRA_HPXL_VLN);
-	writel((var->yres << 16) | var->xres,
+		break;
+	default:
+		;
+	}
+#else
+		writel((var->yres << 16) | (var->xres),
 			dfli->reg_base + LCD_SPU_GRA_HPXL_VLN);
+#endif
 
-	if (info->fixed_output)
+	if (info->fixed_output) {
 		writel((info->out_vmode.yres << 16) | info->out_vmode.xres,
 				dfli->reg_base + LCD_SPU_GZM_HPXL_VLN);
+	}
 	else
 		writel((var->yres << 16) | var->xres,
 				dfli->reg_base + LCD_SPU_GZM_HPXL_VLN);
@@ -941,7 +1003,8 @@ static void dovefb_set_defaults(struct dovefb_layer_info *dfli)
 {
 	writel(0x80000001, dfli->reg_base + LCD_CFG_SCLK_DIV);
 	writel(0x00000000, dfli->reg_base + LCD_SPU_BLANKCOLOR);
-	writel(dfli->info->io_pin_allocation,
+	writel(dfli->info->io_pin_allocation |
+		(0x3 << 18),
 			dfli->reg_base + SPU_IOPAD_CONTROL);
 	writel(0x00000000, dfli->reg_base + LCD_CFG_GRA_START_ADDR1);
 	writel(0x00000000, dfli->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
diff --git a/drivers/video/marvell/dovefb_ovly.c b/drivers/video/marvell/dovefb_ovly.c
index 6bd9fe5..775f80b 100755
--- a/drivers/video/marvell/dovefb_ovly.c
+++ b/drivers/video/marvell/dovefb_ovly.c
@@ -41,12 +41,17 @@
 
 #include <video/dovefb.h>
 #include <video/dovefbreg.h>
+#include <video/dovefb_display.h>
 #include "dovefb_if.h"
 
 #define MAX_QUEUE_NUM	60
 #define RESET_BUF	0x1
 #define FREE_ENTRY	0x2
 
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+extern struct display_settings lcd_config;
+#endif
 static int dovefb_ovly_set_par(struct fb_info *fi);
 static void set_graphics_start(struct fb_info *fi, int xoffset, int yoffset);
 static void set_dma_control0(struct dovefb_layer_info *dfli);
@@ -549,23 +554,32 @@ static int dovefb_ovly_ioctl(struct fb_info *fi, unsigned int cmd,
 		break;
 	case DOVEFB_IOCTL_GET_FBID:
 		mutex_lock(&dfli->access_ok);
-		copy_to_user(argp, &dfli->cur_fbid, sizeof(unsigned int));
+		if (copy_to_user(argp, &dfli->cur_fbid, sizeof(unsigned int))) {
+			mutex_unlock(&dfli->access_ok);
+			return -EFAULT;
+		}
 		mutex_unlock(&dfli->access_ok);
 		break;
 	case DOVEFB_IOCTL_GET_SRC_MODE:
 		mutex_lock(&dfli->access_ok);
-		copy_to_user(argp, &dfli->src_mode, sizeof(int));
+		if (copy_to_user(argp, &dfli->src_mode, sizeof(int))) {
+			mutex_unlock(&dfli->access_ok);
+			return -EFAULT;
+		}
 		mutex_unlock(&dfli->access_ok);
 		break;
 	case DOVEFB_IOCTL_SET_SRC_MODE:
 		mutex_lock(&dfli->access_ok);
-		copy_from_user(&dfli->src_mode, argp, sizeof(int));
+		if (copy_from_user(&dfli->src_mode, argp, sizeof(int))) {
+			mutex_unlock(&dfli->access_ok);
+			return -EFAULT;
+		}
 		mutex_unlock(&dfli->access_ok);
 		break;
 	case DOVEFB_IOCTL_GET_FBPA:
 		{
 		struct shm_private_info info;
-		int i, index;
+		int index;
 
 		if (copy_from_user(&info, argp,
 		    sizeof(struct shm_private_info)))
@@ -577,7 +591,8 @@ static int dovefb_ovly_ioctl(struct fb_info *fi, unsigned int cmd,
 		/* calc physical address. */
 		info.fb_pa = (unsigned long)(dfli->fb_start_dma+
 				(index*info.width*info.height*MAX_YUV_PIXEL));
-		copy_to_user(argp, &info, sizeof(struct shm_private_info));
+		if (copy_to_user(argp, &info, sizeof(struct shm_private_info)))
+			return -EFAULT;
 
 		break;
 		}
@@ -808,6 +823,11 @@ static void set_dma_control0(struct dovefb_layer_info *dfli)
 	x &= 0xef0fff01;
 
 	/*
+	 * enable horizontal smooth scaling.
+	 */
+	x |= 0x1 << 6;
+
+	/*
 	 * If we are in a pseudo-color mode, we need to enable
 	 * palette lookup.
 	 */
@@ -893,7 +913,8 @@ static void set_graphics_start(struct fb_info *fi, int xoffset, int yoffset)
 	pixel_offset = (yoffset * var->xres_virtual) + xoffset;
 
 	if (dfli->new_addr) {
-		addr = dfli->new_addr;
+		addr = dfli->new_addr +
+			(pixel_offset * (var->bits_per_pixel >> 3));
 	} else {
 		addr = dfli->fb_start_dma +
 			(pixel_offset * (var->bits_per_pixel >> 3));
@@ -928,6 +949,7 @@ static int dovefb_ovly_set_par(struct fb_info *fi)
 	struct fb_var_screeninfo *var = &fi->var;
 	int pix_fmt;
 	int xzoom, yzoom;
+	int xbefzoom;
 
 	/*
 	 * Determine which pixel format we're going to use.
@@ -955,12 +977,31 @@ static int dovefb_ovly_set_par(struct fb_info *fi)
 	/*
 	 * Configure graphics DMA parameters.
 	 */
+#if defined(CONFIG_DOVEFB_DISPLAY_MODE_MODULE) || \
+    defined(CONFIG_DOVEFB_DISPLAY_MODE)
+	switch (lcd_config.display_mode) {
+	case DISPLAY_NORMAL:
+	case DISPLAY_CLONE:
+	case DISPLAY_DUALVIEW:
+		set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
+		xbefzoom = var->xres/2;
+		break;
+	case DISPLAY_EXTENDED:
+		xbefzoom = var->xres/2/2;
+		set_graphics_start(fi, fi->var.xoffset+(var->xres/2), fi->var.yoffset);
+	default:
+		set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
+		xbefzoom = var->xres/2;
+		;
+	}
+#else
+	xbefzoom = var->xres/2;
 	set_graphics_start(fi, fi->var.xoffset, fi->var.yoffset);
-
+#endif
 	if ((dfli->pix_fmt >= 0) && (dfli->pix_fmt < 10)) {
 		writel((var->xres_virtual * var->bits_per_pixel) >> 3,
 			dfli->reg_base + LCD_SPU_DMA_PITCH_YC);
-		writel((var->yres << 16) | var->xres,
+		writel((var->yres << 16) | xbefzoom,
 			dfli->reg_base + LCD_SPU_DMA_HPXL_VLN);
 		writel((var->yres << 16) | var->xres,
 			dfli->reg_base + LCD_SPU_DZM_HPXL_VLN);
@@ -978,7 +1019,7 @@ static int dovefb_ovly_set_par(struct fb_info *fi)
 				dfli->reg_base + LCD_SPU_DMA_PITCH_UV);
 		}
 
-		writel((var->yres << 16) | var->xres,
+		writel((var->yres << 16) | (xbefzoom*2),
 			dfli->reg_base + LCD_SPU_DMA_HPXL_VLN);
 		if (info->fixed_output == 0) {
 			yzoom = dfli->surface.viewPortInfo.zoomYSize;
-- 
1.6.0.4





More information about the kernel-team mailing list