diff options
Diffstat (limited to 'drivers/video')
27 files changed, 827 insertions, 157 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 702eb933cf8..e0ef3328942 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -825,30 +825,48 @@ config FB_I810_I2C help config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" + tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL + select I2C_ALGOBIT if FB_INTEL_I2C + select I2C if FB_INTEL_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G chipsets. + 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets. Say Y if you have and plan to use such a board. - To compile this driver as a module, choose M here: the + If you say Y here and want DDC/I2C support you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section. + + If you say M here then "I2C support" and "I2C bit-banging support" + can be build either as modules or built-in. + + To compile this driver as a module, choose M here: the module will be called intelfb. + For more information, please read <file:Documentation/fb/intelfb.txt> + config FB_INTEL_DEBUG - bool "Intel driver Debug Messages" + bool "Intel driver Debug Messages" depends on FB_INTEL ---help--- Say Y here if you want the Intel driver to output all sorts of debugging informations to provide to the maintainer when something goes wrong. +config FB_INTEL_I2C + bool "DDC/I2C for Intel framebuffer support" + depends on FB_INTEL + default y + help + Say Y here if you want DDC/I2C support for your on-board Intel graphics. + config FB_MATROX tristate "Matrox acceleration" depends on FB && PCI diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c index afd146f5f68..397005eb392 100644 --- a/drivers/video/S3triofb.c +++ b/drivers/video/S3triofb.c @@ -349,30 +349,30 @@ static void __init s3triofb_of_init(struct device_node *dp) s3trio_name[sizeof(s3trio_name)-1] = '\0'; strcpy(fb_fix.id, s3trio_name); - if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL + if((pp = get_property(dp, "vendor-id", &len)) != NULL && *pp!=PCI_VENDOR_ID_S3) { printk("%s: can't find S3 Trio board\n", dp->full_name); return; } - if((pp = (int *)get_property(dp, "device-id", &len)) != NULL + if((pp = get_property(dp, "device-id", &len)) != NULL && *pp!=PCI_DEVICE_ID_S3_TRIO) { printk("%s: can't find S3 Trio board\n", dp->full_name); return; } - if ((pp = (int *)get_property(dp, "depth", &len)) != NULL + if ((pp = get_property(dp, "depth", &len)) != NULL && len == sizeof(int) && *pp != 8) { printk("%s: can't use depth = %d\n", dp->full_name, *pp); return; } - if ((pp = (int *)get_property(dp, "width", &len)) != NULL + if ((pp = get_property(dp, "width", &len)) != NULL && len == sizeof(int)) fb_var.xres = fb_var.xres_virtual = *pp; - if ((pp = (int *)get_property(dp, "height", &len)) != NULL + if ((pp = get_property(dp, "height", &len)) != NULL && len == sizeof(int)) fb_var.yres = fb_var.yres_virtual = *pp; - if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL + if ((pp = get_property(dp, "linebytes", &len)) != NULL && len == sizeof(int)) fb_fix.line_length = *pp; else diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 8e3400d5dd2..0ed577e7cc2 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -413,11 +413,11 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo) static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) { struct device_node *dp = rinfo->of_node; - u32 *val; + const u32 *val; if (dp == NULL) return -ENODEV; - val = (u32 *) get_property(dp, "ATY,RefCLK", NULL); + val = get_property(dp, "ATY,RefCLK", NULL); if (!val || !*val) { printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); return -EINVAL; @@ -425,11 +425,11 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) rinfo->pll.ref_clk = (*val) / 10; - val = (u32 *) get_property(dp, "ATY,SCLK", NULL); + val = get_property(dp, "ATY,SCLK", NULL); if (val && *val) rinfo->pll.sclk = (*val) / 10; - val = (u32 *) get_property(dp, "ATY,MCLK", NULL); + val = get_property(dp, "ATY,MCLK", NULL); if (val && *val) rinfo->pll.mclk = (*val) / 10; diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 98c05bc0de4..ea531a6f45d 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -64,13 +64,13 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ { static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID2", NULL }; - u8 *pedid = NULL; - u8 *pmt = NULL; + const u8 *pedid = NULL; + const u8 *pmt = NULL; u8 *tmp; int i, mt = MT_NONE; RTRACE("analyzing OF properties...\n"); - pmt = (u8 *)get_property(dp, "display-type", NULL); + pmt = get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; RTRACE("display-type: %s\n", pmt); @@ -89,7 +89,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ } for (i = 0; propnames[i] != NULL; ++i) { - pedid = (u8 *)get_property(dp, propnames[i], NULL); + pedid = get_property(dp, propnames[i], NULL); if (pedid != NULL) break; } @@ -124,14 +124,14 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ return MT_NONE; if (rinfo->has_CRTC2) { - char *pname; + const char *pname; int len, second = 0; dp = dp->child; do { if (!dp) return MT_NONE; - pname = (char *)get_property(dp, "name", NULL); + pname = get_property(dp, "name", NULL); if (!pname) return MT_NONE; len = strlen(pname); diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index f31e606a2de..365de5dcc88 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -1268,7 +1268,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) 0x21320032, 0xa1320032, 0x21320032, 0xffffffff, 0x31320032 }; - u32 *mrtable = default_mrtable; + const u32 *mrtable = default_mrtable; int i, mrtable_size = ARRAY_SIZE(default_mrtable); mdelay(30); @@ -1287,7 +1287,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) if (rinfo->of_node != NULL) { int size; - mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size); + mrtable = get_property(rinfo->of_node, "ATY,MRT", &size); if (mrtable) mrtable_size = size >> 2; else @@ -2621,25 +2621,28 @@ static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo) } -int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) +int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; int i; - if (state.event == pdev->dev.power.power_state.event) + if (mesg.event == pdev->dev.power.power_state.event) return 0; - printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n", - pci_name(pdev), state.event); + printk(KERN_DEBUG "radeonfb (%s): suspending for event: %d...\n", + pci_name(pdev), mesg.event); /* For suspend-to-disk, we cheat here. We don't suspend anything and * let fbcon continue drawing until we are all set. That shouldn't * really cause any problem at this point, provided that the wakeup * code knows that any state in memory may not match the HW */ - if (state.event == PM_EVENT_FREEZE) + switch (mesg.event) { + case PM_EVENT_FREEZE: /* about to take snapshot */ + case PM_EVENT_PRETHAW: /* before restoring snapshot */ goto done; + } acquire_console_sem(); @@ -2706,7 +2709,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) release_console_sem(); done: - pdev->dev.power.power_state = state; + pdev->dev.power.power_state = mesg; return 0; } diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index ffc72ae3ada..fe1488374f6 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -20,7 +20,7 @@ #include <asm/cpu/dac.h> #include <asm/hp6xx/hp6xx.h> -#include <asm/hd64461/hd64461.h> +#include <asm/hd64461.h> #define HP680_MAX_INTENSITY 255 #define HP680_DEFAULT_INTENSITY 10 @@ -163,6 +163,6 @@ static void __exit hp680bl_exit(void) module_init(hp680bl_init); module_exit(hp680bl_exit); -MODULE_AUTHOR("Andriy Skulysh <askulysh@image.kiev.ua>"); +MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index caf1eca199b..628571c63ba 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -33,19 +33,19 @@ static unsigned long locomolcd_flags; static void locomolcd_on(int comadj) { - locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1); + locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1); mdelay(2); - locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1); + locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1); mdelay(2); locomo_m62332_senddata(locomolcd_dev, comadj, 0); mdelay(5); - locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1); + locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1); mdelay(10); /* TFTCRST | CPSOUT=0 | CPSEN */ @@ -58,8 +58,8 @@ static void locomolcd_on(int comadj) locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC); mdelay(10); - locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1); + locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1); } static void locomolcd_off(int comadj) @@ -68,16 +68,16 @@ static void locomolcd_off(int comadj) locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC); mdelay(1); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); mdelay(110); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); mdelay(700); /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */ locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0); - locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); + locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); } void locomolcd_power(int on) @@ -167,14 +167,14 @@ static int locomolcd_resume(struct locomo_dev *dev) #define locomolcd_resume NULL #endif -static int locomolcd_probe(struct locomo_dev *dev) +static int locomolcd_probe(struct locomo_dev *ldev) { unsigned long flags; local_irq_save(flags); - locomolcd_dev = dev; + locomolcd_dev = ldev; - locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0); + locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); /* the poodle_lcd_power function is called for the first time * from fs_initcall, which is before locomo is activated. diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 4444bef68fb..aa3935df852 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 390439b3d89..1b4f75d1f8a 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3197,11 +3197,11 @@ static void fbcon_exit(void) return; #ifdef CONFIG_ATARI - free_irq(IRQ_AUTO_4, fbcon_vbl_handler); + free_irq(IRQ_AUTO_4, fb_vbl_handler); #endif #ifdef CONFIG_MAC if (MACH_IS_MAC && vbl_detected) - free_irq(IRQ_MAC_VBL, fbcon_vbl_handler); + free_irq(IRQ_MAC_VBL, fb_vbl_handler); #endif kfree((void *)softback_buf); diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 4f78f234473..c151dcf6878 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -397,6 +397,12 @@ static ssize_t store_bl_curve(struct class_device *class_device, u8 tmp_curve[FB_BACKLIGHT_LEVELS]; unsigned int i; + /* Some drivers don't use framebuffer_alloc(), but those also + * don't have backlights. + */ + if (!fb_info || !fb_info->bl_dev) + return -ENODEV; + if (count != (FB_BACKLIGHT_LEVELS / 8 * 24)) return -EINVAL; @@ -430,6 +436,12 @@ static ssize_t show_bl_curve(struct class_device *class_device, char *buf) ssize_t len = 0; unsigned int i; + /* Some drivers don't use framebuffer_alloc(), but those also + * don't have backlights. + */ + if (!fb_info || !fb_info->bl_dev) + return -ENODEV; + mutex_lock(&fb_info->bl_mutex); for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) len += snprintf(&buf[len], PAGE_SIZE, diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 4cc6b454265..3afb472763c 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -4,7 +4,7 @@ * (C) 1999 Mihai Spatar * (C) 2000 YAEGASHI Takeshi * (C) 2003, 2004 Paul Mundt - * (C) 2003, 2004 Andriy Skulysh + * (C) 2003, 2004, 2006 Andriy Skulysh * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -20,18 +20,16 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/fb.h> #include <asm/machvec.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/hd64461/hd64461.h> - -#ifdef MACH_HP600 +#include <asm/hd64461.h> #include <asm/cpu/dac.h> #include <asm/hp6xx/hp6xx.h> -#endif #define WIDTH 640 @@ -45,7 +43,6 @@ static struct fb_var_screeninfo hitfb_var __initdata = { static struct fb_fix_screeninfo hitfb_fix __initdata = { .id = "Hitachi HD64461", .type = FB_TYPE_PACKED_PIXELS, - .ypanstep = 8, .accel = FB_ACCEL_NONE, }; @@ -73,26 +70,14 @@ static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, if (truecolor) saddr <<= 1; - fb_writew(width, HD64461_BBTDWR); - fb_writew(height, HD64461_BBTDHR); + fb_writew(width-1, HD64461_BBTDWR); + fb_writew(height-1, HD64461_BBTDHR); fb_writew(saddr & 0xffff, HD64461_BBTDSARL); fb_writew(saddr >> 16, HD64461_BBTDSARH); } -static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, - u16 width, u16 height, u16 color) -{ - hitfb_accel_set_dest(truecolor, dx, dy, width, height); - - fb_writew(0x00f0, HD64461_BBTROPR); - fb_writew(16, HD64461_BBTMDR); - fb_writew(color, HD64461_GRSCR); - - hitfb_accel_start(truecolor); -} - static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u16 dy, u16 width, u16 height, u16 rop, u32 mask_addr) @@ -100,6 +85,8 @@ static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u32 saddr, daddr; u32 maddr = 0; + height--; + width--; fb_writew(rop, HD64461_BBTROPR); if ((sy < dy) || ((sy == dy) && (sx <= dx))) { saddr = WIDTH * (sy + height) + sx + width; @@ -146,6 +133,7 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (rect->rop != ROP_COPY) cfb_fillrect(p, rect); else { + hitfb_accel_wait(); fb_writew(0x00f0, HD64461_BBTROPR); fb_writew(16, HD64461_BBTMDR); @@ -161,16 +149,15 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) rect->height); hitfb_accel_start(0); } - hitfb_accel_wait(); } } static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { + hitfb_accel_wait(); hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, area->dx, area->dy, area->width, area->height, 0x00cc, 0); - hitfb_accel_wait(); } static int hitfb_pan_display(struct fb_var_screeninfo *var, @@ -182,7 +169,7 @@ static int hitfb_pan_display(struct fb_var_screeninfo *var, if (xoffset != 0) return -EINVAL; - fb_writew(yoffset, HD64461_LCDCBAR); + fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR); return 0; } @@ -192,12 +179,6 @@ int hitfb_blank(int blank_mode, struct fb_info *info) unsigned short v; if (blank_mode) { -#ifdef MACH_HP600 - sh_dac_disable(DAC_LCD_BRIGHTNESS); - v = fb_readw(HD64461_GPBDR); - v |= HD64461_GPBDR_LCDOFF; - fb_writew(v, HD64461_GPBDR); -#endif v = fb_readw(HD64461_LDR1); v &= ~HD64461_LDR1_DON; fb_writew(v, HD64461_LDR1); @@ -213,19 +194,18 @@ int hitfb_blank(int blank_mode, struct fb_info *info) v = fb_readw(HD64461_STBCR); v &= ~HD64461_STBCR_SLCDST; fb_writew(v, HD64461_STBCR); -#ifdef MACH_HP600 - sh_dac_enable(DAC_LCD_BRIGHTNESS); - v = fb_readw(HD64461_GPBDR); - v &= ~HD64461_GPBDR_LCDOFF; - fb_writew(v, HD64461_GPBDR); -#endif - v = fb_readw(HD64461_LDR1); - v |= HD64461_LDR1_DON; - fb_writew(v, HD64461_LDR1); v = fb_readw(HD64461_LCDCCR); - v &= ~HD64461_LCDCCR_MOFF; + v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ); fb_writew(v, HD64461_LCDCCR); + + do { + v = fb_readw(HD64461_LCDCCR); + } while(v&HD64461_LCDCCR_STBACK); + + v = fb_readw(HD64461_LDR1); + v |= HD64461_LDR1_DON; + fb_writew(v, HD64461_LDR1); } return 0; } @@ -233,7 +213,7 @@ int hitfb_blank(int blank_mode, struct fb_info *info) static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - if (regno >= info->cmap.len) + if (regno >= 256) return 1; switch (info->var.bits_per_pixel) { @@ -244,6 +224,8 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, fb_writew(blue >> 10, HD64461_CPTWDR); break; case 16: + if (regno >= 16) + return 1; ((u32 *) (info->pseudo_palette))[regno] = ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -252,26 +234,113 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +static int hitfb_sync(struct fb_info *info) +{ + hitfb_accel_wait(); + + return 0; +} + +static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int maxy; + + var->xres = info->var.xres; + var->xres_virtual = info->var.xres; + var->yres = info->var.yres; + + if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16)) + var->bits_per_pixel = info->var.bits_per_pixel; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + maxy = info->fix.smem_len / var->xres; + + if (var->bits_per_pixel == 16) + maxy /= 2; + + if (var->yres_virtual > maxy) + var->yres_virtual = maxy; + + var->xoffset = 0; + var->yoffset = 0; + + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 565 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + } + + return 0; +} + +static int hitfb_set_par(struct fb_info *info) +{ + unsigned short ldr3; + + switch (info->var.bits_per_pixel) { + case 8: + info->fix.line_length = info->var.xres; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.ypanstep = 16; + break; + case 16: + info->fix.line_length = info->var.xres*2; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.ypanstep = 8; + break; + } + + fb_writew(info->fix.line_length, HD64461_LCDCLOR); + ldr3 = fb_readw(HD64461_LDR3); + ldr3 &= ~15; + ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8; + fb_writew(ldr3, HD64461_LDR3); + return 0; +} + static struct fb_ops hitfb_ops = { .owner = THIS_MODULE, + .fb_check_var = hitfb_check_var, + .fb_set_par = hitfb_set_par, .fb_setcolreg = hitfb_setcolreg, .fb_blank = hitfb_blank, + .fb_sync = hitfb_sync, .fb_pan_display = hitfb_pan_display, .fb_fillrect = hitfb_fillrect, .fb_copyarea = hitfb_copyarea, .fb_imageblit = cfb_imageblit, }; -int __init hitfb_init(void) +static int __init hitfb_probe(struct platform_device *dev) { unsigned short lcdclor, ldr3, ldvndr; - int size; if (fb_get_options("hitfb", NULL)) return -ENODEV; + hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000; + hitfb_fix.mmio_len = 0x1000; hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; - hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024; + hitfb_fix.smem_len = 512 * 1024; lcdclor = fb_readw(HD64461_LCDCLOR); ldvndr = fb_readw(HD64461_LDVNDR); @@ -321,12 +390,12 @@ int __init hitfb_init(void) fb_info.var = hitfb_var; fb_info.fix = hitfb_fix; fb_info.pseudo_palette = pseudo_palette; - fb_info.flags = FBINFO_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; fb_info.screen_base = (void *)hitfb_fix.smem_start; - size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16; - fb_alloc_cmap(&fb_info.cmap, size, 0); + fb_alloc_cmap(&fb_info.cmap, 256, 0); if (register_framebuffer(&fb_info) < 0) return -EINVAL; @@ -336,9 +405,75 @@ int __init hitfb_init(void) return 0; } +static int __devexit hitfb_remove(struct platform_device *dev) +{ + return unregister_framebuffer(&fb_info); +} + +#ifdef CONFIG_PM +static int hitfb_suspend(struct platform_device *dev, pm_message_t state) +{ + u16 v; + + hitfb_blank(1,0); + v = fb_readw(HD64461_STBCR); + v |= HD64461_STBCR_SLCKE_IST; + fb_writew(v, HD64461_STBCR); + + return 0; +} + +static int hitfb_resume(struct platform_device *dev) +{ + u16 v; + + v = fb_readw(HD64461_STBCR); + v &= ~HD64461_STBCR_SLCKE_OST; + msleep(100); + v = fb_readw(HD64461_STBCR); + v &= ~HD64461_STBCR_SLCKE_IST; + fb_writew(v, HD64461_STBCR); + hitfb_blank(0,0); + + return 0; +} +#endif + +static struct platform_driver hitfb_driver = { + .probe = hitfb_probe, + .remove = __devexit_p(hitfb_remove), +#ifdef CONFIG_PM + .suspend = hitfb_suspend, + .resume = hitfb_resume, +#endif + .driver = { + .name = "hitfb", + }, +}; + +static struct platform_device hitfb_device = { + .name = "hitfb", + .id = -1, +}; + +static int __init hitfb_init(void) +{ + int ret; + + ret = platform_driver_register(&hitfb_driver); + if (!ret) { + ret = platform_device_register(&hitfb_device); + if (ret) + platform_driver_unregister(&hitfb_driver); + } + return ret; +} + + static void __exit hitfb_exit(void) { - unregister_framebuffer(&fb_info); + platform_device_unregister(&hitfb_device); + platform_driver_unregister(&hitfb_driver); } module_init(hitfb_init); diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index c1f7b49975d..7d06b38e80a 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c @@ -98,7 +98,6 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name) chan->algo.getsda = i810i2c_getsda; chan->algo.getscl = i810i2c_getscl; chan->algo.udelay = 10; - chan->algo.mdelay = 10; chan->algo.timeout = (HZ/2); chan->algo.data = chan; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index a6ca02f2156..d42edaccb84 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1554,15 +1554,17 @@ static struct fb_ops i810fb_ops __devinitdata = { /*********************************************************************** * Power Management * ***********************************************************************/ -static int i810fb_suspend(struct pci_dev *dev, pm_message_t state) +static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg) { struct fb_info *info = pci_get_drvdata(dev); struct i810fb_par *par = info->par; - par->cur_state = state.event; + par->cur_state = mesg.event; - if (state.event == PM_EVENT_FREEZE) { - dev->dev.power.power_state = state; + switch (mesg.event) { + case PM_EVENT_FREEZE: + case PM_EVENT_PRETHAW: + dev->dev.power.power_state = mesg; return 0; } @@ -1578,7 +1580,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t state) pci_save_state(dev); pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); + pci_set_power_state(dev, pci_choose_state(dev, mesg)); release_console_sem(); return 0; diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile index 722d21d6e5c..6c782d3ae1b 100644 --- a/drivers/video/intelfb/Makefile +++ b/drivers/video/intelfb/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_FB_INTEL) += intelfb.o -intelfb-objs := intelfbdrv.o intelfbhw.o +intelfb-y := intelfbdrv.o intelfbhw.o +intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o +intelfb-objs := $(intelfb-y) ifdef CONFIG_FB_INTEL_DEBUG #EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index e290d7460e1..80b94c19a9f 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -6,6 +6,10 @@ #include <linux/agp_backend.h> #include <linux/fb.h> +#ifdef CONFIG_FB_INTEL_I2C +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#endif /*** Version/name ***/ #define INTELFB_VERSION "0.9.4" @@ -115,6 +119,29 @@ /* Intel agpgart driver */ #define AGP_PHYSICAL_MEMORY 2 +/* store information about an Ixxx DVO */ +/* The i830->i865 use multiple DVOs with multiple i2cs */ +/* the i915, i945 have a single sDVO i2c bus - which is different */ +#define MAX_OUTPUTS 6 + +/* these are outputs from the chip - integrated only + external chips are via DVO or SDVO output */ +#define INTELFB_OUTPUT_UNUSED 0 +#define INTELFB_OUTPUT_ANALOG 1 +#define INTELFB_OUTPUT_DVO 2 +#define INTELFB_OUTPUT_SDVO 3 +#define INTELFB_OUTPUT_LVDS 4 +#define INTELFB_OUTPUT_TVOUT 5 + +#define INTELFB_DVO_CHIP_NONE 0 +#define INTELFB_DVO_CHIP_LVDS 1 +#define INTELFB_DVO_CHIP_TMDS 2 +#define INTELFB_DVO_CHIP_TVOUT 4 + +#define INTELFB_OUTPUT_PIPE_NC 0 +#define INTELFB_OUTPUT_PIPE_A 1 +#define INTELFB_OUTPUT_PIPE_B 2 + /*** Data Types ***/ /* supported chipsets */ @@ -195,6 +222,10 @@ struct intelfb_hwstate { u32 mem_mode; u32 fw_blc_0; u32 fw_blc_1; + u16 hwstam; + u16 ier; + u16 iir; + u16 imr; }; struct intelfb_heap_data { @@ -204,6 +235,33 @@ struct intelfb_heap_data { u32 size; // in bytes }; +#ifdef CONFIG_FB_INTEL_I2C +struct intelfb_i2c_chan { + struct intelfb_info *dinfo; + u32 reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; +#endif + +struct intelfb_output_rec { + int type; + int pipe; + int flags; + +#ifdef CONFIG_FB_INTEL_I2C + struct intelfb_i2c_chan i2c_bus; + struct intelfb_i2c_chan ddc_bus; +#endif +}; + +struct intelfb_vsync { + wait_queue_head_t wait; + unsigned int count; + int pan_display; + u32 pan_offset; +}; + struct intelfb_info { struct fb_info *info; struct fb_ops *fbops; @@ -220,7 +278,7 @@ struct intelfb_info { u8 fbmem_gart; /* mtrr support */ - u32 mtrr_reg; + int mtrr_reg; u32 has_mtrr; /* heap data */ @@ -267,6 +325,12 @@ struct intelfb_info { int fixed_mode; int ring_active; int flag; + unsigned long irq_flags; + int open; + + /* vsync */ + struct intelfb_vsync vsync; + spinlock_t int_lock; /* hw cursor */ int cursor_on; @@ -285,12 +349,25 @@ struct intelfb_info { /* index into plls */ int pll_index; + + /* outputs */ + int num_outputs; + struct intelfb_output_rec output[MAX_OUTPUTS]; }; #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM)) +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif + /*** function prototypes ***/ extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); +#ifdef CONFIG_FB_INTEL_I2C +extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo); +extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo); +#endif + #endif /* _INTELFB_H */ diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c new file mode 100644 index 00000000000..c1113d6e941 --- /dev/null +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -0,0 +1,200 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +#include <asm/io.h> + +#include "intelfb.h" +#include "intelfbhw.h" + +/* bit locations in the registers */ +#define SCL_DIR_MASK 0x0001 +#define SCL_DIR 0x0002 +#define SCL_VAL_MASK 0x0004 +#define SCL_VAL_OUT 0x0008 +#define SCL_VAL_IN 0x0010 +#define SDA_DIR_MASK 0x0100 +#define SDA_DIR 0x0200 +#define SDA_VAL_MASK 0x0400 +#define SDA_VAL_OUT 0x0800 +#define SDA_VAL_IN 0x1000 + +static void intelfb_gpio_setscl(void *data, int state) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); + val = INREG(chan->reg); +} + +static void intelfb_gpio_setsda(void *data, int state) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); + val = INREG(chan->reg); +} + +static int intelfb_gpio_getscl(void *data) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, SCL_DIR_MASK); + OUTREG(chan->reg, 0); + val = INREG(chan->reg); + return ((val & SCL_VAL_IN) != 0); +} + +static int intelfb_gpio_getsda(void *data) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, SDA_DIR_MASK); + OUTREG(chan->reg, 0); + val = INREG(chan->reg); + return ((val & SDA_VAL_IN) != 0); +} + +static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, + struct intelfb_i2c_chan *chan, + const u32 reg, const char *name) +{ + int rc; + + chan->dinfo = dinfo; + chan->reg = reg; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_INTELFB; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->dinfo->pdev->dev; + chan->algo.setsda = intelfb_gpio_setsda; + chan->algo.setscl = intelfb_gpio_setscl; + chan->algo.getsda = intelfb_gpio_getsda; + chan->algo.getscl = intelfb_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + intelfb_gpio_setsda(chan, 1); + intelfb_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + DBG_MSG("I2C bus %s registered.\n", name); + else + WRN_MSG("Failed to register I2C bus %s.\n", name); + return rc; +} + +void intelfb_create_i2c_busses(struct intelfb_info *dinfo) +{ + int i = 0; + + /* everyone has at least a single analog output */ + dinfo->num_outputs = 1; + dinfo->output[i].type = INTELFB_OUTPUT_ANALOG; + + /* setup the DDC bus for analog output */ + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A"); + i++; + + /* need to add the output busses for each device + - this function is very incomplete + - i915GM has LVDS and TVOUT for example + */ + switch(dinfo->chipset) { + case INTEL_830M: + case INTEL_845G: + case INTEL_855GM: + case INTEL_865G: + dinfo->output[i].type = INTELFB_OUTPUT_DVO; + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E"); + i++; + break; + case INTEL_915G: + case INTEL_915GM: + /* has some LVDS + tv-out */ + case INTEL_945G: + case INTEL_945GM: + /* SDVO ports have a single control bus - 2 devices */ + dinfo->output[i].type = INTELFB_OUTPUT_SDVO; + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E"); + /* TODO: initialize the SDVO */ +// I830SDVOInit(pScrn, i, DVOB); + i++; + + /* set up SDVOC */ + dinfo->output[i].type = INTELFB_OUTPUT_SDVO; + dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus; + /* TODO: initialize the SDVO */ +// I830SDVOInit(pScrn, i, DVOC); + i++; + break; + } + dinfo->num_outputs = i; +} + +void intelfb_delete_i2c_busses(struct intelfb_info *dinfo) +{ + int i; + + for (i = 0; i < MAX_OUTPUTS; i++) { + if (dinfo->output[i].i2c_bus.dinfo) { + i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter); + dinfo->output[i].i2c_bus.dinfo = NULL; + } + if (dinfo->output[i].ddc_bus.dinfo) { + i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter); + dinfo->output[i].ddc_bus.dinfo = NULL; + } + } +} diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 06af89d44a0..6f9de04193d 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -136,6 +136,8 @@ static void __devinit get_initial_mode(struct intelfb_info *dinfo); static void update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var); +static int intelfb_open(struct fb_info *info, int user); +static int intelfb_release(struct fb_info *info, int user); static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); static int intelfb_set_par(struct fb_info *info); @@ -194,6 +196,8 @@ static int num_registered = 0; /* fb ops */ static struct fb_ops intel_fb_ops = { .owner = THIS_MODULE, + .fb_open = intelfb_open, + .fb_release = intelfb_release, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, @@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo) if (!dinfo) return; + intelfbhw_disable_irq(dinfo); + fb_dealloc_cmap(&dinfo->info->cmap); kfree(dinfo->info->pixmap.addr); @@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo) agp_free_memory(dinfo->gtt_ring_mem); } +#ifdef CONFIG_FB_INTEL_I2C + /* un-register I2C bus */ + intelfb_delete_i2c_busses(dinfo); +#endif + if (dinfo->mmio_base) iounmap((void __iomem *)dinfo->mmio_base); if (dinfo->aperture.virtual) @@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) if (bailearly == 5) bailout(dinfo); +#ifdef CONFIG_FB_INTEL_I2C + /* register I2C bus */ + intelfb_create_i2c_busses(dinfo); +#endif + if (bailearly == 6) bailout(dinfo); @@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) } dinfo->registered = 1; + dinfo->open = 0; + + init_waitqueue_head(&dinfo->vsync.wait); + spin_lock_init(&dinfo->int_lock); + dinfo->irq_flags = 0; + dinfo->vsync.pan_display = 0; + dinfo->vsync.pan_offset = 0; return 0; @@ -1188,6 +1211,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) ***************************************************************/ static int +intelfb_open(struct fb_info *info, int user) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + + if (user) { + dinfo->open++; + } + + return 0; +} + +static int +intelfb_release(struct fb_info *info, int user) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + + if (user) { + dinfo->open--; + msleep(1); + if (!dinfo->open) { + intelfbhw_disable_irq(dinfo); + } + } + + return 0; +} + +static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { int change_var = 0; @@ -1433,6 +1484,19 @@ static int intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { int retval = 0; + struct intelfb_info *dinfo = GET_DINFO(info); + u32 pipe = 0; + + switch (cmd) { + case FBIO_WAITFORVSYNC: + if (get_user(pipe, (__u32 __user *)arg)) + return -EFAULT; + + retval = intelfbhw_wait_for_vsync(dinfo, pipe); + break; + default: + break; + } return retval; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 2a9322f9cfd..f887f1efd3f 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -32,6 +32,7 @@ #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> +#include <linux/interrupt.h> #include <asm/io.h> @@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) offset += dinfo->fb.offset << 12; - OUTREG(DSPABASE, offset); + dinfo->vsync.pan_offset = offset; + if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) { + dinfo->vsync.pan_display = 1; + } else { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, offset); + } return 0; } @@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, hw->fw_blc_0 = INREG(FW_BLC_0); hw->fw_blc_1 = INREG(FW_BLC_1); + hw->hwstam = INREG16(HWSTAM); + hw->ier = INREG16(IER); + hw->iir = INREG16(IIR); + hw->imr = INREG16(IMR); + return 0; } @@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd return vco / p; } +#if REGDUMP static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) { @@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) *o_p1 = p1; *o_p2 = p2; } +#endif void @@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); + printk(" HWSTAM 0x%04x\n", hw->hwstam); + printk(" IER 0x%04x\n", hw->ier); + printk(" IIR 0x%04x\n", hw->iir); + printk(" IMR 0x%04x\n", hw->imr); printk("hw state dump end\n"); #endif } @@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { addr += 16; } } + +static irqreturn_t +intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { + int handled = 0; + u16 tmp; + struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; + + spin_lock(&dinfo->int_lock); + + tmp = INREG16(IIR); + tmp &= VSYNC_PIPE_A_INTERRUPT; + + if (tmp == 0) { + spin_unlock(&dinfo->int_lock); + return IRQ_RETVAL(handled); + } + + OUTREG16(IIR, tmp); + + if (tmp & VSYNC_PIPE_A_INTERRUPT) { + dinfo->vsync.count++; + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } + wake_up_interruptible(&dinfo->vsync.wait); + handled = 1; + } + + spin_unlock(&dinfo->int_lock); + + return IRQ_RETVAL(handled); +} + +int +intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { + + if (!test_and_set_bit(0, &dinfo->irq_flags)) { + if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) { + clear_bit(0, &dinfo->irq_flags); + return -EINVAL; + } + + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xfffe); + OUTREG16(IMR, 0x0); + OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); + spin_unlock_irq(&dinfo->int_lock); + } else if (reenable) { + u16 ier; + + spin_lock_irq(&dinfo->int_lock); + ier = INREG16(IER); + if ((ier & VSYNC_PIPE_A_INTERRUPT)) { + DBG_MSG("someone disabled the IRQ [%08X]\n", ier); + OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); + } + spin_unlock_irq(&dinfo->int_lock); + } + return 0; +} + +void +intelfbhw_disable_irq(struct intelfb_info *dinfo) { + u16 tmp; + + if (test_and_clear_bit(0, &dinfo->irq_flags)) { + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xffff); + OUTREG16(IMR, 0xffff); + OUTREG16(IER, 0x0); + + tmp = INREG16(IIR); + OUTREG16(IIR, tmp); + spin_unlock_irq(&dinfo->int_lock); + + free_irq(dinfo->pdev->irq, dinfo); + } +} + +int +intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { + struct intelfb_vsync *vsync; + unsigned int count; + int ret; + + switch (pipe) { + case 0: + vsync = &dinfo->vsync; + break; + default: + return -ENODEV; + } + + ret = intelfbhw_enable_irq(dinfo, 0); + if (ret) { + return ret; + } + + count = vsync->count; + ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + intelfbhw_enable_irq(dinfo, 1); + DBG_MSG("wait_for_vsync timed out!\n"); + return -ETIMEDOUT; + } + + return 0; +} diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 10acda098b7..8c54ba8fbdd 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -88,6 +88,19 @@ #define INSTDONE 0x2090 #define PRI_RING_EMPTY 1 +#define HWSTAM 0x2098 +#define IER 0x20A0 +#define IIR 0x20A4 +#define IMR 0x20A8 +#define VSYNC_PIPE_A_INTERRUPT (1 << 7) +#define PIPE_A_EVENT_INTERRUPT (1 << 4) +#define VSYNC_PIPE_B_INTERRUPT (1 << 5) +#define PIPE_B_EVENT_INTERRUPT (1 << 4) +#define HOST_PORT_EVENT_INTERRUPT (1 << 3) +#define CAPTURE_EVENT_INTERRUPT (1 << 2) +#define USER_DEFINED_INTERRUPT (1 << 1) +#define BREAKPOINT_INTERRUPT 1 + #define INSTPM 0x20c0 #define SYNC_FLUSH_ENABLE (1 << 5) @@ -113,6 +126,12 @@ #define FW_DISPC_BL_SHIFT 8 #define FW_DISPC_BL_MASK 0x7 +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 // this may be external DDC on i830 +#define GPIOD 0x501C // this is DVO DDC +#define GPIOE 0x5020 // this is DVO i2C +#define GPIOF 0x5024 /* PLL registers */ #define VGA0_DIVISOR 0x06000 @@ -468,9 +487,12 @@ /* I/O macros */ #define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr))) +#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr))) #define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr))) #define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \ (addr))) +#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \ + (addr))) #define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \ (addr))) @@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, u8 *data); extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); +extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); +extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); +extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); #endif /* _INTELFBHW_H */ diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 57abbae5520..795c1a99a68 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -95,12 +95,12 @@ static struct i2c_adapter matrox_i2c_adapter_template = static struct i2c_algo_bit_data matrox_i2c_algo_template = { - NULL, - matroxfb_gpio_setsda, - matroxfb_gpio_setscl, - matroxfb_gpio_getsda, - matroxfb_gpio_getscl, - 10, 10, 100, + .setsda = matroxfb_gpio_setsda, + .setscl = matroxfb_gpio_setscl, + .getsda = matroxfb_gpio_getsda, + .getscl = matroxfb_gpio_getscl, + .udelay = 10, + .timeout = 100, }; static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c index 8209106e26e..d9af88c2b58 100644 --- a/drivers/video/nvidia/nv_of.c +++ b/drivers/video/nvidia/nv_of.c @@ -32,7 +32,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) { struct nvidia_par *par = info->par; struct device_node *parent, *dp; - unsigned char *pedid = NULL; + const unsigned char *pedid = NULL; static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; @@ -42,20 +42,19 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) if (parent == NULL) return -1; if (par->twoHeads) { - char *pname; + const char *pname; int len; for (dp = NULL; (dp = of_get_next_child(parent, dp)) != NULL;) { - pname = (char *)get_property(dp, "name", NULL); + pname = get_property(dp, "name", NULL); if (!pname) continue; len = strlen(pname); if ((pname[len-1] == 'A' && conn == 1) || (pname[len-1] == 'B' && conn == 2)) { for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) - get_property(dp, propnames[i], + pedid = get_property(dp, propnames[i], NULL); if (pedid != NULL) break; @@ -67,8 +66,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) } if (pedid == NULL) { for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) - get_property(parent, propnames[i], NULL); + pedid = get_property(parent, propnames[i], NULL); if (pedid != NULL) break; } diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index d4f85011787..f8cd4c519ae 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -950,24 +950,25 @@ static struct fb_ops nvidia_fb_ops = { }; #ifdef CONFIG_PM -static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state) +static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) { struct fb_info *info = pci_get_drvdata(dev); struct nvidia_par *par = info->par; + if (mesg.event == PM_EVENT_PRETHAW) + mesg.event = PM_EVENT_FREEZE; acquire_console_sem(); - par->pm_state = state.event; + par->pm_state = mesg.event; - if (state.event == PM_EVENT_FREEZE) { - dev->dev.power.power_state = state; - } else { + if (mesg.event == PM_EVENT_SUSPEND) { fb_set_suspend(info, 1); nvidiafb_blank(FB_BLANK_POWERDOWN, info); nvidia_write_regs(par, &par->SavedReg); pci_save_state(dev); pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); + pci_set_power_state(dev, pci_choose_state(dev, mesg)); } + dev->dev.power.power_state = mesg; release_console_sem(); return 0; diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 0013311e056..bad0e98fb3b 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -409,30 +409,30 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) unsigned int flags, rsize, addr_prop = 0; unsigned long max_size = 0; u64 rstart, address = OF_BAD_ADDR; - u32 *pp, *addrp, *up; + const u32 *pp, *addrp, *up; u64 asize; - pp = (u32 *)get_property(dp, "linux,bootx-depth", &len); + pp = get_property(dp, "linux,bootx-depth", &len); if (pp == NULL) - pp = (u32 *)get_property(dp, "depth", &len); + pp = get_property(dp, "depth", &len); if (pp && len == sizeof(u32)) depth = *pp; - pp = (u32 *)get_property(dp, "linux,bootx-width", &len); + pp = get_property(dp, "linux,bootx-width", &len); if (pp == NULL) - pp = (u32 *)get_property(dp, "width", &len); + pp = get_property(dp, "width", &len); if (pp && len == sizeof(u32)) width = *pp; - pp = (u32 *)get_property(dp, "linux,bootx-height", &len); + pp = get_property(dp, "linux,bootx-height", &len); if (pp == NULL) - pp = (u32 *)get_property(dp, "height", &len); + pp = get_property(dp, "height", &len); if (pp && len == sizeof(u32)) height = *pp; - pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len); + pp = get_property(dp, "linux,bootx-linebytes", &len); if (pp == NULL) - pp = (u32 *)get_property(dp, "linebytes", &len); + pp = get_property(dp, "linebytes", &len); if (pp && len == sizeof(u32)) pitch = *pp; else @@ -450,9 +450,9 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) * ranges and pick one that is both big enough and if possible encloses * the "address" property. If none match, we pick the biggest */ - up = (u32 *)get_property(dp, "linux,bootx-addr", &len); + up = get_property(dp, "linux,bootx-addr", &len); if (up == NULL) - up = (u32 *)get_property(dp, "address", &len); + up = get_property(dp, "address", &len); if (up && len == sizeof(u32)) addr_prop = *up; diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 940ba2be55e..78dc59a1751 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -187,7 +187,7 @@ static short do_blank = 0; /* (Un)Blank the screen */ static unsigned int is_blanked = 0; /* Is the screen blanked? */ #ifdef CONFIG_SH_STORE_QUEUES -static struct sq_mapping *pvr2fb_map; +static unsigned long pvr2fb_map; #endif #ifdef CONFIG_SH_DMA @@ -213,15 +213,17 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp); static int pvr2_init_cable(void); static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size); +#ifdef CONFIG_SH_DMA static ssize_t pvr2fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos); +#endif static struct fb_ops pvr2fb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = pvr2fb_setcolreg, - .fb_blank = pvr2fb_blank, - .fb_check_var = pvr2fb_check_var, - .fb_set_par = pvr2fb_set_par, + .owner = THIS_MODULE, + .fb_setcolreg = pvr2fb_setcolreg, + .fb_blank = pvr2fb_blank, + .fb_check_var = pvr2fb_check_var, + .fb_set_par = pvr2fb_set_par, #ifdef CONFIG_SH_DMA .fb_write = pvr2fb_write, #endif @@ -783,7 +785,7 @@ static int __init pvr2fb_common_init(void) goto out_err; } - fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len); + fb_memset(fb_info->screen_base, 0, pvr2_fix.smem_len); pvr2_fix.ypanstep = nopan ? 0 : 1; pvr2_fix.ywrapstep = nowrap ? 0 : 1; @@ -820,7 +822,7 @@ static int __init pvr2fb_common_init(void) modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", fb_info->node, fb_info->var.xres, fb_info->var.yres, - fb_info->var.bits_per_pixel, + fb_info->var.bits_per_pixel, get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), (char *)pvr2_get_param(cables, NULL, cable_type, 3), (char *)pvr2_get_param(outputs, NULL, video_output, 3)); @@ -829,10 +831,10 @@ static int __init 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); + fb_info->fix.id, pgprot_val(PAGE_SHARED)); printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n", - fb_info->node, pvr2fb_map->sq_addr); + fb_info->node, pvr2fb_map); #endif return 0; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 8ddb47a56b0..4acde4f7dbf 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1826,8 +1826,8 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) { struct riva_par *par = info->par; struct device_node *dp; - unsigned char *pedid = NULL; - unsigned char *disptype = NULL; + const unsigned char *pedid = NULL; + const unsigned char *disptype = NULL; static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; int i; @@ -1835,14 +1835,13 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) NVTRACE_ENTER(); dp = pci_device_to_OF_node(pd); for (; dp != NULL; dp = dp->child) { - disptype = (unsigned char *)get_property(dp, "display-type", NULL); + disptype = get_property(dp, "display-type", NULL); if (disptype == NULL) continue; if (strncmp(disptype, "LCD", 3) != 0) continue; for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) - get_property(dp, propnames[i], NULL); + pedid = get_property(dp, propnames[i], NULL); if (pedid != NULL) { par->EDID = pedid; NVTRACE("LCD found.\n"); diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index e83befd16d6..d7d810dbf0b 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -148,7 +148,6 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pcidev->dev; chan->algo.udelay = 40; - chan->algo.mdelay = 5; chan->algo.timeout = 20; chan->algo.data = chan; diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 461e094e7b4..82b3deaae02 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2323,24 +2323,24 @@ static void __devexit savagefb_remove(struct pci_dev *dev) } } -static int savagefb_suspend(struct pci_dev* dev, pm_message_t state) +static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg) { struct fb_info *info = pci_get_drvdata(dev); struct savagefb_par *par = info->par; DBG("savagefb_suspend"); - - par->pm_state = state.event; + if (mesg.event == PM_EVENT_PRETHAW) + mesg.event = PM_EVENT_FREEZE; + par->pm_state = mesg.event; + dev->dev.power.power_state = mesg; /* * For PM_EVENT_FREEZE, do not power down so the console * can remain active. */ - if (state.event == PM_EVENT_FREEZE) { - dev->dev.power.power_state = state; + if (mesg.event == PM_EVENT_FREEZE) return 0; - } acquire_console_sem(); fb_set_suspend(info, 1); @@ -2353,7 +2353,7 @@ static int savagefb_suspend(struct pci_dev* dev, pm_message_t state) savage_disable_mmio(par); pci_save_state(dev); pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); + pci_set_power_state(dev, pci_choose_state(dev, mesg)); release_console_sem(); return 0; |