[PATCH 12/23] add new dispaly mode, such as extended mode, dualview, clone mode
Brad Figg
brad.figg at canonical.com
Thu Aug 27 23:20:52 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/dovefb_display.c | 273 ++++++++++++++++++++++++++++++++
1 files changed, 273 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/marvell/dovefb_display.c
diff --git a/drivers/video/marvell/dovefb_display.c b/drivers/video/marvell/dovefb_display.c
new file mode 100644
index 0000000..bfae83d
--- /dev/null
+++ b/drivers/video/marvell/dovefb_display.c
@@ -0,0 +1,273 @@
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/vt.h>
+#include <linux/init.h>
+#include <linux/linux_logo.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+#include <linux/fb.h>
+
+#include <video/dovefb.h>
+#include <video/dovefbreg.h>
+#include <video/dovedcon.h>
+#include <video/dovefb_display.h>
+
+/*
+ * LCD controll register physical address
+ */
+static unsigned int lcd_regbase;
+//module_param(lcd_regbase, uint, 0xf1810000);
+module_param(lcd_regbase, uint, 0);
+MODULE_PARM_DESC(lcd_regbase, "LCD controller register base");
+
+/*
+ * 0 means lcd0 = regbase + 0x0, lcd1 = regbase + 0x10000;
+ * 1 means lcd0 = regbase + 0x10000, lcd1 = regbase + 0x0;
+ */
+static unsigned int lcdseq;
+module_param(lcdseq, uint, 1);
+MODULE_PARM_DESC(lcdseq, "LCD sequence");
+
+extern struct display_settings lcd_config;
+extern struct class *fb_class;
+static void *lcd0_regbase;
+static void *lcd1_regbase;
+static void *dcon_regbase;
+
+static void set_graphics_start(struct fb_info *fi, int xoffset, int yoffset,
+ struct fb_info *newfi)
+{
+ struct dovefb_layer_info *dfli = fi->par;
+ struct fb_var_screeninfo *var = &fi->var;
+ int pixel_offset;
+ unsigned long addr;
+ unsigned int x;
+
+ if (newfi) {
+ fi->var.xres_virtual = newfi->var.xres_virtual;
+
+ 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);
+ }
+ pixel_offset = (yoffset * var->xres_virtual) + xoffset;
+
+ if (newfi) {
+ struct dovefb_layer_info *newdfli = newfi->par;
+ addr = newdfli->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+ } else
+ addr = dfli->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+
+ writel(addr, dfli->reg_base + LCD_CFG_GRA_START_ADDR0);
+}
+
+static void dcon_portb(uint mode)
+{
+ unsigned int ctrl0;
+
+ /* enable lcd0 pass to PortB */
+ ctrl0 = readl(dcon_regbase+DCON_CTRL0);
+ ctrl0 &= ~(0x3 << 8);
+ ctrl0 |= (mode << 8);
+ writel(ctrl0, dcon_regbase+DCON_CTRL0);
+
+}
+
+static void set_back(void)
+{
+ //uint x;
+ struct dovefb_layer_info *dfli0_gfx = lcd_config.lcd0_gfx->par;
+ //struct dovefb_layer_info *dfli0_vid = lcd_config.lcd0_vid->par;
+ struct dovefb_layer_info *dfli1_gfx = lcd_config.lcd1_gfx->par;
+ //struct dovefb_layer_info *dfli1_vid = lcd_config.lcd1_vid->par;
+
+ struct fb_var_screeninfo *var0_gfx = &lcd_config.lcd0_gfx->var;
+ //struct fb_var_screeninfo *var0_vid = &lcd_config.lcd0_vid->var;
+ struct fb_var_screeninfo *var1_gfx = &lcd_config.lcd1_gfx->var;
+ //struct fb_var_screeninfo *var1_vid = &lcd_config.lcd1_vid->var;
+
+ /* set lcd0 src scan line */
+ writel((var0_gfx->yres << 16) | (var0_gfx->xres),
+ dfli0_gfx->reg_base + LCD_SPU_GRA_HPXL_VLN);
+
+ /* set lcd1 src scan line */
+ writel((var1_gfx->yres << 16) | (var1_gfx->xres),
+ dfli1_gfx->reg_base + LCD_SPU_GRA_HPXL_VLN);
+
+ /* set lcd1 refresh whole area. */
+ set_graphics_start(lcd_config.lcd1_gfx,
+ var1_gfx->xoffset,
+ var1_gfx->yoffset,
+ lcd_config.lcd0_gfx);
+}
+
+static int setup_display(struct display_settings *config)
+{
+ //uint x;
+ //struct dovefb_layer_info *dfli0_gfx = lcd_config.lcd0_gfx->par;
+ //struct dovefb_layer_info *dfli0_vid = lcd_config.lcd0_vid->par;
+ //struct dovefb_layer_info *dfli1_gfx = lcd_config.lcd1_gfx->par;
+ //struct dovefb_layer_info *dfli1_vid = lcd_config.lcd1_vid->par;
+
+ //struct fb_var_screeninfo *var0_gfx = &lcd_config.lcd0_gfx->var;
+ //struct fb_var_screeninfo *var0_vid = &lcd_config.lcd0_vid->var;
+ struct fb_var_screeninfo *var1_gfx = &lcd_config.lcd1_gfx->var;
+ //struct fb_var_screeninfo *var1_vid = &lcd_config.lcd1_vid->var;
+
+ if (!config)
+ return -1;
+
+ switch (config->display_mode) {
+ case DISPLAY_EXTENDED:
+ dcon_portb(0);
+ printk(KERN_INFO "configure to EXTENDED Mode\n");
+ /* set lcd0 src scan line */
+// writel((var0_gfx->yres << 16) | (var0_gfx->xres*lcd_config.extend_ratio/4),
+// dfli0_gfx->reg_base + LCD_SPU_GRA_HPXL_VLN);
+
+ /* set lcd1 src scan line */
+// writel((var1_gfx->yres << 16) | (var1_gfx->xres*lcd_config.extend_ratio/4),
+// dfli1_gfx->reg_base + LCD_SPU_GRA_HPXL_VLN);
+
+ /* set lcd1 refresh second half portion. */
+ set_graphics_start(lcd_config.lcd1_gfx,
+ var1_gfx->xoffset+(var1_gfx->xres),
+ var1_gfx->yoffset, lcd_config.lcd0_gfx);
+ break;
+ case DISPLAY_NORMAL:
+ printk(KERN_INFO "configure to NORMAL Mode\n");
+ dcon_portb(0);
+ set_back();
+ set_graphics_start(lcd_config.lcd1_gfx,
+ var1_gfx->xoffset,
+ var1_gfx->yoffset, 0);
+
+ /* switch lcd1's buffer addr back. */
+ break;
+ case DISPLAY_CLONE:
+ printk(KERN_INFO "configure to CLONE Mode\n");
+ dcon_portb(1);
+ set_back();
+#if 0 // test code, set lcd0 to dump16bit mode.
+#endif
+ break;
+ case DISPLAY_DUALVIEW:
+ printk(KERN_INFO "configure to DUALVIEW Mode\n");
+ dcon_portb(0);
+ set_back();
+ break;
+ default:
+ ;
+ }
+
+
+ return 0;
+}
+
+static long display_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct display_settings config;
+ switch (cmd) {
+ case 0: /* configure display mode. */
+ printk(KERN_INFO "driver set display config.\n");
+
+ /* Get data from user space. */
+ if (copy_from_user(&config, (void *)arg, sizeof(struct display_settings)))
+ return -EFAULT;
+
+ lcd_config.display_mode = config.display_mode;
+ lcd_config.extend_ratio = config.extend_ratio;
+
+#ifdef MTL_DEBUG
+ printk("Get mode = %d\n", lcd_config.display_mode);
+ printk("Get ratio = %d\n", lcd_config.extend_ratio);
+#endif
+ /*
+ * set up lcd0
+ */
+ //printk(KERN_INFO "case 0 .... driver set display config.\n");
+ setup_display(&lcd_config);
+ break;
+ case 1:
+ /* get display configuration. */
+ printk(KERN_INFO "get display config.\n");
+ if (copy_to_user((void *)arg, &lcd_config, sizeof(struct display_settings)))
+ return -EFAULT;
+ break;
+ default:
+ printk(KERN_ERR "Unknown command\n");
+ }
+
+ return 0;
+}
+
+static const struct file_operations display_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = display_ioctl,
+};
+
+
+static int __init
+dovefb_display_init(void)
+{
+#ifdef MTL_DEBUG
+ uint x;
+
+ printk(KERN_INFO "lcd_regbase = 0x%08x\n", lcd_regbase);
+ printk(KERN_INFO "lcdseq = %d, 1^lcdseq = %d\n", lcdseq, 1^lcdseq);
+ printk(KERN_INFO "lcdseq = %d, 0^lcdseq = %d\n", lcdseq, 0^lcdseq);
+#endif
+ printk(KERN_WARNING "dovefb_display_init\n");
+
+ /* register character. */
+ if (register_chrdev(30, "display tools", &display_fops))
+ printk("unable to get major %d for fb devs\n", 30);
+
+ if (lcd_regbase) {
+ /* remap to ctrl registers. */
+ lcd0_regbase = ioremap_nocache( lcd_regbase + (0x10000*(0^lcdseq)), (0x10000 - 1));
+ lcd1_regbase = ioremap_nocache( lcd_regbase + (0x10000*(1^lcdseq)), (0x10000 - 1));
+ dcon_regbase = ioremap_nocache( lcd_regbase + 0x20000, (0x10000 - 1));
+#ifdef MTL_DEBUG
+ x = readl( lcd0_regbase + 0x104 );
+ printk(KERN_INFO "debug lcd0 reg 0x104 = 0x%08x\n", x);
+ x = readl( lcd1_regbase + 0x108 );
+ printk(KERN_INFO "debug lcd0 reg 0x104 = 0x%08x\n", x);
+ x = readl( dcon_regbase + 0x000 );
+ printk(KERN_INFO "debug dcon reg 0x000 = 0x%08x\n", x);
+#endif
+ }
+
+ printk(KERN_WARNING "dovefb_display driver init ok.\n");
+ return 0;
+}
+
+static void __exit
+dovefb_display_exit(void)
+{
+ iounmap(lcd0_regbase);
+ iounmap(lcd1_regbase);
+ iounmap(dcon_regbase);
+ unregister_chrdev(30, "display tools");
+ printk(KERN_WARNING "dovefb_display driver unload OK.\n");
+}
+
+module_init(dovefb_display_init);
+module_exit(dovefb_display_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Display mode driver");
+
--
1.6.0.4
More information about the kernel-team
mailing list