diff options
Diffstat (limited to 'drivers/video')
48 files changed, 2804 insertions, 2776 deletions
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 7f907fb23b8a..0b17824b0eb5 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -471,9 +471,11 @@ int __init mc68x328fb_init(void) fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - fb_alloc_cmap(&fb_info.cmap, 256, 0); + if (fb_alloc_cmap(&fb_info.cmap, 256, 0)) + return -ENOMEM; if (register_framebuffer(&fb_info) < 0) { + fb_dealloc_cmap(&fb_info.cmap); return -EINVAL; } @@ -494,6 +496,7 @@ module_init(mc68x328fb_init); static void __exit mc68x328fb_cleanup(void) { unregister_framebuffer(&fb_info); + fb_dealloc_cmap(&fb_info.cmap); } module_exit(mc68x328fb_cleanup); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 41c27a44bd82..7826bdce4bbe 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1550,6 +1550,7 @@ config FB_3DFX select FB_CFB_IMAGEBLIT select FB_CFB_FILLRECT select FB_CFB_COPYAREA + select FB_MODE_HELPERS help This driver supports graphics boards with the 3Dfx Banshee, Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have @@ -1565,6 +1566,14 @@ config FB_3DFX_ACCEL This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer device driver with acceleration functions. +config FB_3DFX_I2C + bool "Enable DDC/I2C support" + depends on FB_3DFX && EXPERIMENTAL + select FB_DDC + default y + help + Say Y here if you want DDC/I2C support for your 3dfx Voodoo3. + config FB_VOODOO1 tristate "3Dfx Voodoo Graphics (sst1) support" depends on FB && PCI @@ -1597,32 +1606,8 @@ config FB_VT8623 Driver for CastleRock integrated graphics core in the VIA VT8623 [Apollo CLE266] chipset. -config FB_CYBLA - tristate "Cyberblade/i1 support" - depends on FB && PCI && X86_32 && !64BIT - select FB_CFB_IMAGEBLIT - ---help--- - This driver is supposed to support the Trident Cyberblade/i1 - graphics core integrated in the VIA VT8601A North Bridge, - also known as VIA Apollo PLE133. - - Status: - - Developed, tested and working on EPIA 5000 and EPIA 800. - - Does work reliable on all systems with CRT/LCD connected to - normal VGA ports. - - Should work on systems that do use the internal LCD port, but - this is absolutely not tested. - - Character imageblit, copyarea and rectangle fill are hw accelerated, - ypan scrolling is used by default. - - Please do read <file:Documentation/fb/cyblafb/*>. - - To compile this driver as a module, choose M here: the - module will be called cyblafb. - config FB_TRIDENT - tristate "Trident support" + tristate "Trident/CyberXXX/CyberBlade support" depends on FB && PCI select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -1633,21 +1618,14 @@ config FB_TRIDENT and Blade XP. There are also integrated versions of these chips called CyberXXXX, CyberImage or CyberBlade. These chips are mostly found in laptops - but also on some motherboards. For more information, read - <file:Documentation/fb/tridentfb.txt> + but also on some motherboards including early VIA EPIA motherboards. + For more information, read <file:Documentation/fb/tridentfb.txt> Say Y if you have such a graphics board. To compile this driver as a module, choose M here: the module will be called tridentfb. -config FB_TRIDENT_ACCEL - bool "Trident Acceleration functions (EXPERIMENTAL)" - depends on FB_TRIDENT && EXPERIMENTAL - ---help--- - This will compile the Trident frame buffer device with - acceleration functions. - config FB_ARK tristate "ARK 2000PV support" depends on FB && PCI @@ -1920,6 +1898,30 @@ config FB_TMIO_ACCELL depends on FB_TMIO default y +config FB_S3C + tristate "Samsung S3C framebuffer support" + depends on FB && ARCH_S3C64XX + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the built-in FB controller in the Samsung + SoC line from the S3C2443 onwards, including the S3C2416, S3C2450, + and the S3C64XX series such as the S3C6400 and S3C6410. + + These chips all have the same basic framebuffer design with the + actual capabilities depending on the chip. For instance the S3C6400 + and S3C6410 support 4 hardware windows whereas the S3C24XX series + currently only have two. + + Currently the support is only for the S3C6400 and S3C6410 SoCs. + +config FB_S3C_DEBUG_REGWRITE + bool "Debug register writes" + depends on FB_S3C + ---help--- + Show all register writes via printk(KERN_DEBUG) + config FB_S3C2410 tristate "S3C2410 LCD framebuffer support" depends on FB && ARCH_S3C2410 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index bb265eca7d57..0dbd6c68d76b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HECUBA) += hecubafb.o +obj-$(CONFIG_FB_N411) += n411.o obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_XVR500) += sunxvr500.o obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o @@ -110,6 +111,7 @@ obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_SH7760) += sh7760fb.o obj-$(CONFIG_FB_IMX) += imxfb.o +obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 4e046fed1380..61050ab14128 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -408,7 +408,9 @@ static int clcdfb_register(struct clcd_fb *fb) /* * Allocate colourmap. */ - fb_alloc_cmap(&fb->fb.cmap, 256, 0); + ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0); + if (ret) + goto unmap; /* * Ensure interrupts are disabled. @@ -426,6 +428,8 @@ static int clcdfb_register(struct clcd_fb *fb) printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); + fb_dealloc_cmap(&fb->fb.cmap); + unmap: iounmap(fb->regs); free_clk: clk_put(fb->clk); @@ -485,6 +489,8 @@ static int clcdfb_remove(struct amba_device *dev) clcdfb_disable(fb); unregister_framebuffer(&fb->fb); + if (fb->fb.cmap.len) + fb_dealloc_cmap(&fb->fb.cmap); iounmap(fb->regs); clk_put(fb->clk); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 100f23661465..82bedd7f7789 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -2437,7 +2437,9 @@ default_chipset: goto amifb_error; } - fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); + err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); + if (err) + goto amifb_error; if (register_framebuffer(&fb_info) < 0) { err = -EINVAL; @@ -2456,7 +2458,8 @@ amifb_error: static void amifb_deinit(void) { - fb_dealloc_cmap(&fb_info.cmap); + if (fb_info.cmap.len) + fb_dealloc_cmap(&fb_info.cmap); chipfree(); if (videomemory) iounmap((void*)videomemory); diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 314d18694b6a..d583bea608fd 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -470,7 +470,7 @@ static void ark_dac_read_regs(void *data, u8 *code, int count) while (count != 0) { - vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); + vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); code[1] = vga_r(NULL, dac_regs[code[0] & 3]); count--; code += 2; @@ -485,7 +485,7 @@ static void ark_dac_write_regs(void *data, u8 *code, int count) while (count != 0) { - vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); + vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); vga_w(NULL, dac_regs[code[0] & 3], code[1]); count--; code += 2; diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index 1fd22f460b0f..1a1f946d8fef 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -505,19 +505,27 @@ static struct fb_var_screeninfo asiliantfb_var __devinitdata = { .vsync_len = 2, }; -static void __devinit init_asiliant(struct fb_info *p, unsigned long addr) +static int __devinit init_asiliant(struct fb_info *p, unsigned long addr) { + int err; + p->fix = asiliantfb_fix; p->fix.smem_start = addr; p->var = asiliantfb_var; p->fbops = &asiliantfb_ops; p->flags = FBINFO_DEFAULT; - fb_alloc_cmap(&p->cmap, 256, 0); + err = fb_alloc_cmap(&p->cmap, 256, 0); + if (err) { + printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n"); + return err; + } - if (register_framebuffer(p) < 0) { + err = register_framebuffer(p); + if (err < 0) { printk(KERN_ERR "C&T 69000 framebuffer failed to register\n"); - return; + fb_dealloc_cmap(&p->cmap); + return err; } printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n", @@ -532,6 +540,7 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { unsigned long addr, size; struct fb_info *p; + int err; if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) return -ENODEV; @@ -560,7 +569,13 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) pci_write_config_dword(dp, 4, 0x02800083); writeb(3, p->screen_base + 0x400784); - init_asiliant(p, addr); + err = init_asiliant(p, addr); + if (err) { + iounmap(p->screen_base); + release_mem_region(addr, size); + framebuffer_release(p); + return err; + } pci_set_drvdata(dp, p); return 0; @@ -571,6 +586,7 @@ static void __devexit asiliantfb_remove(struct pci_dev *dp) struct fb_info *p = pci_get_drvdata(dp); unregister_framebuffer(p); + fb_dealloc_cmap(&p->cmap); iounmap(p->screen_base); release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); pci_set_drvdata(dp, NULL); diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index a8f60c33863c..0cc9724e61a2 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -39,7 +39,8 @@ void aty_reset_engine(const struct atyfb_par *par) { /* reset engine */ aty_st_le32(GEN_TEST_CNTL, - aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par); + aty_ld_le32(GEN_TEST_CNTL, par) & + ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par); /* enable engine */ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index faf95da8fcbc..04c710804bb0 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c @@ -77,9 +77,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (par->asleep) return -EPERM; - /* Hide cursor */ wait_for_fifo(1, par); - aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par); + if (cursor->enable) + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) + | HWCURSOR_ENABLE, par); + else + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) + & ~HWCURSOR_ENABLE, par); /* set position */ if (cursor->set & FB_CUR_SETPOS) { @@ -109,7 +113,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) y<<=1; h<<=1; } - wait_for_fifo(4, par); + wait_for_fifo(3, par); aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par); aty_st_le32(CUR_HORZ_VERT_OFF, ((u32) (64 - h + yoff) << 16) | xoff, par); @@ -177,11 +181,6 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) } } - if (cursor->enable) { - wait_for_fifo(1, par); - aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) - | HWCURSOR_ENABLE, par); - } return 0; } diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index c6d7cc76516f..97a1f095f327 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -89,6 +89,9 @@ static struct radeon_device_id radeon_workaround_list[] = { BUGFIX("Acer Aspire 2010", PCI_VENDOR_ID_AI, 0x0061, radeon_pm_off, radeon_reinitialize_M10), + BUGFIX("Acer Travelmate 290D/292LMi", + PCI_VENDOR_ID_AI, 0x005a, + radeon_pm_off, radeon_reinitialize_M10), { .ident = NULL } }; @@ -2582,7 +2585,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) * calling pci_set_power_state() */ radeonfb_whack_power_state(rinfo, PCI_D2); - pci_set_power_state(rinfo->pdev, PCI_D2); + __pci_complete_power_transition(rinfo->pdev, PCI_D2); } else { printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n", pci_name(rinfo->pdev)); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 72facb9eb7db..f9d19be05540 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -84,6 +84,15 @@ config LCD_TOSA If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its LCD. +config LCD_HP700 + tristate "HP Jornada 700 series LCD Driver" + depends on LCD_CLASS_DEVICE + depends on SA1100_JORNADA720_SSP && !PREEMPT + default y + help + If you have an HP Jornada 700 series handheld (710/720/728) + say Y to enable LCD control driver. + # # Backlight # @@ -157,6 +166,15 @@ config BACKLIGHT_HP680 If you have a HP Jornada 680, say y to enable the backlight driver. +config BACKLIGHT_HP700 + tristate "HP Jornada 700 series Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE + depends on SA1100_JORNADA720_SSP && !PREEMPT + default y + help + If you have an HP Jornada 700 series, + say Y to include backlight control driver. + config BACKLIGHT_PROGEAR tristate "Frontpath ProGear Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE && PCI && X86 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 63d759498165..4eb178c1d684 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o +obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o obj-$(CONFIG_LCD_ILI9320) += ili9320.o obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o @@ -12,6 +13,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o +obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 157057c79ca3..dd37cbcaf8ce 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -35,6 +35,8 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); + if (!lock_fb_info(evdata->info)) + return -ENODEV; mutex_lock(&bd->ops_lock); if (bd->ops) if (!bd->ops->check_fb || @@ -47,6 +49,7 @@ static int fb_notifier_callback(struct notifier_block *self, backlight_update_status(bd); } mutex_unlock(&bd->ops_lock); + unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c new file mode 100644 index 000000000000..c3ebb6b41ce1 --- /dev/null +++ b/drivers/video/backlight/jornada720_bl.c @@ -0,0 +1,161 @@ +/* + * + * Backlight driver for HP Jornada 700 series (710/720/728) + * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 or any later version as published by the Free Software Foundation. + * + */ + +#include <linux/backlight.h> +#include <linux/device.h> +#include <linux/fb.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <mach/jornada720.h> +#include <mach/hardware.h> + +#include <video/s1d13xxxfb.h> + +#define BL_MAX_BRIGHT 255 +#define BL_DEF_BRIGHT 25 + +static int jornada_bl_get_brightness(struct backlight_device *bd) +{ + int ret; + + /* check if backlight is on */ + if (!(PPSR & PPC_LDD1)) + return 0; + + jornada_ssp_start(); + + /* cmd should return txdummy */ + ret = jornada_ssp_byte(GETBRIGHTNESS); + + if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) { + printk(KERN_ERR "bl : get brightness timeout\n"); + jornada_ssp_end(); + return -ETIMEDOUT; + } else /* exchange txdummy for value */ + ret = jornada_ssp_byte(TXDUMMY); + + jornada_ssp_end(); + + return (BL_MAX_BRIGHT - ret); +} + +static int jornada_bl_update_status(struct backlight_device *bd) +{ + int ret = 0; + + jornada_ssp_start(); + + /* If backlight is off then really turn it off */ + if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) { + ret = jornada_ssp_byte(BRIGHTNESSOFF); + if (ret != TXDUMMY) { + printk(KERN_INFO "bl : brightness off timeout\n"); + /* turn off backlight */ + PPSR &= ~PPC_LDD1; + PPDR |= PPC_LDD1; + ret = -ETIMEDOUT; + } + } else /* turn on backlight */ + PPSR |= PPC_LDD1; + + /* send command to our mcu */ + if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) { + printk(KERN_INFO "bl : failed to set brightness\n"); + ret = -ETIMEDOUT; + goto out + } + + /* at this point we expect that the mcu has accepted + our command and is waiting for our new value + please note that maximum brightness is 255, + but due to physical layout it is equal to 0, so we simply + invert the value (MAX VALUE - NEW VALUE). */ + if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) { + printk(KERN_ERR "bl : set brightness failed\n"); + ret = -ETIMEDOUT; + } + + /* If infact we get an TXDUMMY as output we are happy and dont + make any further comments about it */ +out: + jornada_ssp_end(); + + return ret; +} + +static struct backlight_ops jornada_bl_ops = { + .get_brightness = jornada_bl_get_brightness, + .update_status = jornada_bl_update_status, + .options = BL_CORE_SUSPENDRESUME, +}; + +static int jornada_bl_probe(struct platform_device *pdev) +{ + int ret; + struct backlight_device *bd; + + bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops); + + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); + printk(KERN_ERR "bl : failed to register device, err=%x\n", ret); + return ret; + } + + bd->props.power = FB_BLANK_UNBLANK; + bd->props.brightness = BL_DEF_BRIGHT; + /* note. make sure max brightness is set otherwise + you will get seemingly non-related errors when + trying to change brightness */ + bd->props.max_brightness = BL_MAX_BRIGHT; + jornada_bl_update_status(bd); + + platform_set_drvdata(pdev, bd); + printk(KERN_INFO "HP Jornada 700 series backlight driver\n"); + + return 0; +} + +static int jornada_bl_remove(struct platform_device *pdev) +{ + struct backlight_device *bd = platform_get_drvdata(pdev); + + backlight_device_unregister(bd); + + return 0; +} + +static struct platform_driver jornada_bl_driver = { + .probe = jornada_bl_probe, + .remove = jornada_bl_remove, + .driver = { + .name = "jornada_bl", + }, +}; + +int __init jornada_bl_init(void) +{ + return platform_driver_register(&jornada_bl_driver); +} + +void __exit jornada_bl_exit(void) +{ + platform_driver_unregister(&jornada_bl_driver); +} + +MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>"); +MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver"); +MODULE_LICENSE("GPL"); + +module_init(jornada_bl_init); +module_exit(jornada_bl_exit); diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c new file mode 100644 index 000000000000..cbbb167fd268 --- /dev/null +++ b/drivers/video/backlight/jornada720_lcd.c @@ -0,0 +1,153 @@ +/* + * + * LCD driver for HP Jornada 700 series (710/720/728) + * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 or any later version as published by the Free Software Foundation. + * + */ + +#include <linux/device.h> +#include <linux/fb.h> +#include <linux/kernel.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> + +#include <mach/jornada720.h> +#include <mach/hardware.h> + +#include <video/s1d13xxxfb.h> + +#define LCD_MAX_CONTRAST 0xff +#define LCD_DEF_CONTRAST 0x80 + +static int jornada_lcd_get_power(struct lcd_device *dev) +{ + /* LDD2 in PPC = LCD POWER */ + if (PPSR & PPC_LDD2) + return FB_BLANK_UNBLANK; /* PW ON */ + else + return FB_BLANK_POWERDOWN; /* PW OFF */ +} + +static int jornada_lcd_get_contrast(struct lcd_device *dev) +{ + int ret; + + if (jornada_lcd_get_power(dev) != FB_BLANK_UNBLANK) + return 0; + + jornada_ssp_start(); + + if (jornada_ssp_byte(GETCONTRAST) != TXDUMMY) { + printk(KERN_ERR "lcd: get contrast failed\n"); + jornada_ssp_end(); + return -ETIMEDOUT; + } else { + ret = jornada_ssp_byte(TXDUMMY); + jornada_ssp_end(); + return ret; + } +} + +static int jornada_lcd_set_contrast(struct lcd_device *dev, int value) +{ + int ret; + + jornada_ssp_start(); + + /* start by sending our set contrast cmd to mcu */ + ret = jornada_ssp_byte(SETCONTRAST); + + /* push the new value */ + if (jornada_ssp_byte(value) != TXDUMMY) { + printk(KERN_ERR "lcd : set contrast failed\n"); + jornada_ssp_end(); + return -ETIMEDOUT; + } + + /* if we get here we can assume everything went well */ + jornada_ssp_end(); + + return 0; +} + +static int jornada_lcd_set_power(struct lcd_device *dev, int power) +{ + if (power != FB_BLANK_UNBLANK) { + PPSR &= ~PPC_LDD2; + PPDR |= PPC_LDD2; + } else + PPSR |= PPC_LDD2; + + return 0; +} + +static struct lcd_ops jornada_lcd_props = { + .get_contrast = jornada_lcd_get_contrast, + .set_contrast = jornada_lcd_set_contrast, + .get_power = jornada_lcd_get_power, + .set_power = jornada_lcd_set_power, +}; + +static int jornada_lcd_probe(struct platform_device *pdev) +{ + struct lcd_device *lcd_device; + int ret; + + lcd_device = lcd_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_lcd_props); + + if (IS_ERR(lcd_device)) { + ret = PTR_ERR(lcd_device); + printk(KERN_ERR "lcd : failed to register device\n"); + return ret; + } + + platform_set_drvdata(pdev, lcd_device); + + /* lets set our default values */ + jornada_lcd_set_contrast(lcd_device, LCD_DEF_CONTRAST); + jornada_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); + /* give it some time to startup */ + msleep(100); + + return 0; +} + +static int jornada_lcd_remove(struct platform_device *pdev) +{ + struct lcd_device *lcd_device = platform_get_drvdata(pdev); + + lcd_device_unregister(lcd_device); + + return 0; +} + +static struct platform_driver jornada_lcd_driver = { + .probe = jornada_lcd_probe, + .remove = jornada_lcd_remove, + .driver = { + .name = "jornada_lcd", + }, +}; + +int __init jornada_lcd_init(void) +{ + return platform_driver_register(&jornada_lcd_driver); +} + +void __exit jornada_lcd_exit(void) +{ + platform_driver_unregister(&jornada_lcd_driver); +} + +MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); +MODULE_DESCRIPTION("HP Jornada 710/720/728 LCD driver"); +MODULE_LICENSE("GPL"); + +module_init(jornada_lcd_init); +module_exit(jornada_lcd_exit); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index b6449470106c..0bb13df0fa89 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -40,6 +40,8 @@ static int fb_notifier_callback(struct notifier_block *self, if (!ld->ops) return 0; + if (!lock_fb_info(evdata->info)) + return -ENODEV; mutex_lock(&ld->ops_lock); if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { if (event == FB_EVENT_BLANK) { @@ -51,6 +53,7 @@ static int fb_notifier_callback(struct notifier_block *self, } } mutex_unlock(&ld->ops_lock); + unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 65864c500455..3bb4c0a50c62 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -27,73 +27,192 @@ static struct backlight_device *mbp_backlight_device; -static struct dmi_system_id __initdata mbp_device_table[] = { +/* Structure to be passed to the DMI_MATCH function. */ +struct dmi_match_data { + /* I/O resource to allocate. */ + unsigned long iostart; + unsigned long iolen; + /* Backlight operations structure. */ + struct backlight_ops backlight_ops; +}; + +/* Module parameters. */ +static int debug; +module_param_named(debug, debug, int, 0644); +MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); + +/* + * Implementation for MacBooks with Intel chipset. + */ +static int intel_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", + intensity); + + outb(0x04 | (intensity << 4), 0xb3); + outb(0xbf, 0xb2); + return 0; +} + +static int intel_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0xb3); + outb(0xbf, 0xb2); + intensity = inb(0xb3) >> 4; + + if (debug) + printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct dmi_match_data intel_chipset_data = { + .iostart = 0xb2, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = intel_chipset_get_intensity, + .update_status = intel_chipset_send_intensity, + } +}; + +/* + * Implementation for MacBooks with Nvidia chipset. + */ +static int nvidia_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", + intensity); + + outb(0x04 | (intensity << 4), 0x52f); + outb(0xbf, 0x52e); + return 0; +} + +static int nvidia_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0x52f); + outb(0xbf, 0x52e); + intensity = inb(0x52f) >> 4; + + if (debug) + printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct dmi_match_data nvidia_chipset_data = { + .iostart = 0x52e, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nvidia_chipset_get_intensity, + .update_status = nvidia_chipset_send_intensity + } +}; + +/* + * DMI matching. + */ +static /* const */ struct dmi_match_data *driver_data; + +static int mbp_dmi_match(const struct dmi_system_id *id) +{ + driver_data = id->driver_data; + + printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident); + return 1; +} + +static const struct dmi_system_id __initdata mbp_device_table[] = { { - .ident = "3,1", - .matches = { + .callback = mbp_dmi_match, + .ident = "MacBookPro 3,1", + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), }, + .driver_data = (void *)&intel_chipset_data, }, { - .ident = "3,2", - .matches = { + .callback = mbp_dmi_match, + .ident = "MacBookPro 3,2", + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), }, + .driver_data = (void *)&intel_chipset_data, }, { - .ident = "4,1", - .matches = { + .callback = mbp_dmi_match, + .ident = "MacBookPro 4,1", + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBook 5,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookAir 2,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 5,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, }, { } }; -static int mbp_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - outb(0x04 | (intensity << 4), 0xb3); - outb(0xbf, 0xb2); - - return 0; -} - -static int mbp_get_intensity(struct backlight_device *bd) -{ - outb(0x03, 0xb3); - outb(0xbf, 0xb2); - return inb(0xb3) >> 4; -} - -static struct backlight_ops mbp_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = mbp_get_intensity, - .update_status = mbp_send_intensity, -}; - static int __init mbp_init(void) { if (!dmi_check_system(mbp_device_table)) return -ENODEV; - if (!request_region(0xb2, 2, "Macbook Pro backlight")) + if (!request_region(driver_data->iostart, driver_data->iolen, + "Macbook Pro backlight")) return -ENXIO; mbp_backlight_device = backlight_device_register("mbp_backlight", - NULL, NULL, - &mbp_ops); + NULL, NULL, &driver_data->backlight_ops); if (IS_ERR(mbp_backlight_device)) { - release_region(0xb2, 2); + release_region(driver_data->iostart, driver_data->iolen); return PTR_ERR(mbp_backlight_device); } mbp_backlight_device->props.max_brightness = 15; mbp_backlight_device->props.brightness = - mbp_get_intensity(mbp_backlight_device); + driver_data->backlight_ops.get_brightness(mbp_backlight_device); backlight_update_status(mbp_backlight_device); return 0; @@ -103,7 +222,7 @@ static void __exit mbp_exit(void) { backlight_device_unregister(mbp_backlight_device); - release_region(0xb2, 2); + release_region(driver_data->iostart, driver_data->iolen); } module_init(mbp_init); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index ea07258565f0..e641584e212e 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -3,7 +3,7 @@ * * simple PWM based backlight control, board code has to setup * 1) pin configuration so PWM waveforms can output - * 2) platform_data casts to the PWM id (0/1/2/3 on PXA) + * 2) platform_data being correctly configured * * 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 @@ -97,7 +97,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) } else dev_dbg(&pdev->dev, "got pwm for backlight\n"); - bl = backlight_device_register(pdev->name, &pdev->dev, + bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb, &pwm_backlight_ops); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index a2aa6ddffbe2..d42e385f091c 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -34,8 +34,6 @@ * */ -#define CIRRUSFB_VERSION "2.0-pre2" - #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -72,20 +70,9 @@ * */ -/* enable debug output? */ -/* #define CIRRUSFB_DEBUG 1 */ - /* disable runtime assertions? */ /* #define CIRRUSFB_NDEBUG */ -/* debug output */ -#ifdef CIRRUSFB_DEBUG -#define DPRINTK(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - /* debugging assertions */ #ifndef CIRRUSFB_NDEBUG #define assert(expr) \ @@ -108,14 +95,15 @@ /* board types */ enum cirrus_board { BT_NONE = 0, - BT_SD64, - BT_PICCOLO, - BT_PICASSO, - BT_SPECTRUM, + BT_SD64, /* GD5434 */ + BT_PICCOLO, /* GD5426 */ + BT_PICASSO, /* GD5426 or GD5428 */ + BT_SPECTRUM, /* GD5426 or GD5428 */ BT_PICASSO4, /* GD5446 */ BT_ALPINE, /* GD543x/4x */ BT_GD5480, - BT_LAGUNA, /* GD546x */ + BT_LAGUNA, /* GD5462/64 */ + BT_LAGUNAB, /* GD5465 */ }; /* @@ -150,15 +138,17 @@ static const struct cirrusfb_board_info_rec { .maxclock = { /* guess */ /* the SD64/P4 have a higher max. videoclock */ - 140000, 140000, 140000, 140000, 140000, + 135100, 135100, 85500, 85500, 0 }, .init_sr07 = true, .init_sr1f = true, .scrn_start_bit19 = true, .sr07 = 0xF0, .sr07_1bpp = 0xF0, + .sr07_1bpp_mux = 0xF6, .sr07_8bpp = 0xF1, - .sr1f = 0x20 + .sr07_8bpp_mux = 0xF7, + .sr1f = 0x1E }, [BT_PICCOLO] = { .name = "CL Piccolo", @@ -210,9 +200,11 @@ static const struct cirrusfb_board_info_rec { .init_sr07 = true, .init_sr1f = false, .scrn_start_bit19 = true, - .sr07 = 0x20, - .sr07_1bpp = 0x20, - .sr07_8bpp = 0x21, + .sr07 = 0xA0, + .sr07_1bpp = 0xA0, + .sr07_1bpp_mux = 0xA6, + .sr07_8bpp = 0xA1, + .sr07_8bpp_mux = 0xA7, .sr1f = 0 }, [BT_ALPINE] = { @@ -225,8 +217,8 @@ static const struct cirrusfb_board_info_rec { .init_sr1f = true, .scrn_start_bit19 = true, .sr07 = 0xA0, - .sr07_1bpp = 0xA1, - .sr07_1bpp_mux = 0xA7, + .sr07_1bpp = 0xA0, + .sr07_1bpp_mux = 0xA6, .sr07_8bpp = 0xA1, .sr07_8bpp_mux = 0xA7, .sr1f = 0x1C @@ -247,8 +239,18 @@ static const struct cirrusfb_board_info_rec { [BT_LAGUNA] = { .name = "CL Laguna", .maxclock = { - /* guess */ - 135100, 135100, 135100, 135100, 135100, + /* taken from X11 code */ + 170000, 170000, 170000, 170000, 135100, + }, + .init_sr07 = false, + .init_sr1f = false, + .scrn_start_bit19 = true, + }, + [BT_LAGUNAB] = { + .name = "CL Laguna AGP", + .maxclock = { + /* taken from X11 code */ + 170000, 250000, 170000, 170000, 135100, }, .init_sr07 = false, .init_sr1f = false, @@ -262,8 +264,8 @@ static const struct cirrusfb_board_info_rec { static struct pci_device_id cirrusfb_pci_table[] = { CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE), - CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE), - CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64), CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */ CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE), CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE), @@ -271,7 +273,7 @@ static struct pci_device_id cirrusfb_pci_table[] = { CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */ CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */ CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */ - CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/ + CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/ { 0, } }; MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); @@ -326,10 +328,6 @@ static const struct { }; #endif /* CONFIG_ZORRO */ -struct cirrusfb_regs { - int multiplexing; -}; - #ifdef CIRRUSFB_DEBUG enum cirrusfb_dbg_reg_class { CRT, @@ -340,10 +338,12 @@ enum cirrusfb_dbg_reg_class { /* info about board */ struct cirrusfb_info { u8 __iomem *regbase; + u8 __iomem *laguna_mmio; enum cirrus_board btype; unsigned char SFR; /* Shadow of special function register */ - struct cirrusfb_regs currentmode; + int multiplexing; + int doubleVCLK; int blank_mode; u32 pseudo_palette[16]; @@ -357,43 +357,8 @@ static char *mode_option __devinitdata = "640x480@60"; /**** BEGIN PROTOTYPES ******************************************************/ /*--- Interface used by the world ------------------------------------------*/ -static int cirrusfb_init(void); -#ifndef MODULE -static int cirrusfb_setup(char *options); -#endif - -static int cirrusfb_open(struct fb_info *info, int user); -static int cirrusfb_release(struct fb_info *info, int user); -static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); -static int cirrusfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info); -static int cirrusfb_set_par(struct fb_info *info); static int cirrusfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); -static int cirrusfb_blank(int blank_mode, struct fb_info *info); -static void cirrusfb_fillrect(struct fb_info *info, - const struct fb_fillrect *region); -static void cirrusfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area); -static void cirrusfb_imageblit(struct fb_info *info, - const struct fb_image *image); - -/* function table of the above functions */ -static struct fb_ops cirrusfb_ops = { - .owner = THIS_MODULE, - .fb_open = cirrusfb_open, - .fb_release = cirrusfb_release, - .fb_setcolreg = cirrusfb_setcolreg, - .fb_check_var = cirrusfb_check_var, - .fb_set_par = cirrusfb_set_par, - .fb_pan_display = cirrusfb_pan_display, - .fb_blank = cirrusfb_blank, - .fb_fillrect = cirrusfb_fillrect, - .fb_copyarea = cirrusfb_copyarea, - .fb_imageblit = cirrusfb_imageblit, -}; /*--- Internal routines ----------------------------------------------------*/ static void init_vgachip(struct fb_info *info); @@ -421,22 +386,27 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, u_short x, u_short y, u_short width, u_short height, - u_char color, u_short line_length); + u32 fg_color, u32 bg_color, + u_short line_length, u_char blitmode); static void bestclock(long freq, int *nom, int *den, int *div); #ifdef CIRRUSFB_DEBUG -static void cirrusfb_dump(void); -static void cirrusfb_dbg_reg_dump(caddr_t regbase); -static void cirrusfb_dbg_print_regs(caddr_t regbase, +static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase); +static void cirrusfb_dbg_print_regs(struct fb_info *info, + caddr_t regbase, enum cirrusfb_dbg_reg_class reg_class, ...); -static void cirrusfb_dbg_print_byte(const char *name, unsigned char val); #endif /* CIRRUSFB_DEBUG */ /*** END PROTOTYPES ********************************************************/ /*****************************************************************************/ /*** BEGIN Interface Used by the World ***************************************/ +static inline int is_laguna(const struct cirrusfb_info *cinfo) +{ + return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB; +} + static int opencount; /*--- Open /dev/fbx ---------------------------------------------------------*/ @@ -460,85 +430,94 @@ static int cirrusfb_release(struct fb_info *info, int user) /**** BEGIN Hardware specific Routines **************************************/ /* Check if the MCLK is not a better clock source */ -static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq) +static int cirrusfb_check_mclk(struct fb_info *info, long freq) { + struct cirrusfb_info *cinfo = info->par; long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f; /* Read MCLK value */ mclk = (14318 * mclk) >> 3; - DPRINTK("Read MCLK of %ld kHz\n", mclk); + dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk); /* Determine if we should use MCLK instead of VCLK, and if so, what we * should divide it by to get VCLK */ if (abs(freq - mclk) < 250) { - DPRINTK("Using VCLK = MCLK\n"); + dev_dbg(info->device, "Using VCLK = MCLK\n"); return 1; } else if (abs(freq - (mclk / 2)) < 250) { - DPRINTK("Using VCLK = MCLK/2\n"); + dev_dbg(info->device, "Using VCLK = MCLK/2\n"); return 2; } return 0; } -static int cirrusfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, + struct fb_info *info) { - int yres; - /* memory size in pixels */ - unsigned pixels = info->screen_size * 8 / var->bits_per_pixel; + long freq; + long maxclock; + struct cirrusfb_info *cinfo = info->par; + unsigned maxclockidx = var->bits_per_pixel >> 3; - switch (var->bits_per_pixel) { - case 1: - pixels /= 4; - break; /* 8 pixel per byte, only 1/4th of mem usable */ - case 8: - case 16: - case 32: - break; /* 1 pixel == 1 byte */ - default: - printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." - "color depth not supported.\n", - var->xres, var->yres, var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); - return -EINVAL; - } + /* convert from ps to kHz */ + freq = PICOS2KHZ(var->pixclock); - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - /* use highest possible virtual resolution */ - if (var->yres_virtual == -1) { - var->yres_virtual = pixels / var->xres_virtual; + dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); - printk(KERN_INFO "cirrusfb: virtual resolution set to " - "maximum of %dx%d\n", var->xres_virtual, - var->yres_virtual); - } - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; + maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; + cinfo->multiplexing = 0; - if (var->xres_virtual * var->yres_virtual > pixels) { - printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... " - "virtual resolution too high to fit into video memory!\n", - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); + /* If the frequency is greater than we can support, we might be able + * to use multiplexing for the video mode */ + if (freq > maxclock) { + dev_err(info->device, + "Frequency greater than maxclock (%ld kHz)\n", + maxclock); return -EINVAL; } + /* + * Additional constraint: 8bpp uses DAC clock doubling to allow maximum + * pixel clock + */ + if (var->bits_per_pixel == 8) { + switch (cinfo->btype) { + case BT_ALPINE: + case BT_SD64: + case BT_PICASSO4: + if (freq > 85500) + cinfo->multiplexing = 1; + break; + case BT_GD5480: + if (freq > 135100) + cinfo->multiplexing = 1; + break; + default: + break; + } + } - if (var->xoffset < 0) - var->xoffset = 0; - if (var->yoffset < 0) - var->yoffset = 0; + /* If we have a 1MB 5434, we need to put ourselves in a mode where + * the VCLK is double the pixel clock. */ + cinfo->doubleVCLK = 0; + if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ && + var->bits_per_pixel == 16) { + cinfo->doubleVCLK = 1; + } - /* truncate xoffset and yoffset to maximum if too high */ - if (var->xoffset > var->xres_virtual - var->xres) - var->xoffset = var->xres_virtual - var->xres - 1; - if (var->yoffset > var->yres_virtual - var->yres) - var->yoffset = var->yres_virtual - var->yres - 1; + return 0; +} + +static int cirrusfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int yres; + /* memory size in pixels */ + unsigned pixels = info->screen_size * 8 / var->bits_per_pixel; + struct cirrusfb_info *cinfo = info->par; switch (var->bits_per_pixel) { case 1: @@ -550,7 +529,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, case 8: var->red.offset = 0; - var->red.length = 6; + var->red.length = 8; var->green = var->red; var->blue = var->red; break; @@ -561,20 +540,20 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, var->green.offset = -3; var->blue.offset = 8; } else { - var->red.offset = 10; + var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; } var->red.length = 5; - var->green.length = 5; + var->green.length = 6; var->blue.length = 5; break; - case 32: + case 24: if (isPReP) { - var->red.offset = 8; - var->green.offset = 16; - var->blue.offset = 24; + var->red.offset = 0; + var->green.offset = 8; + var->blue.offset = 16; } else { var->red.offset = 16; var->green.offset = 8; @@ -586,12 +565,45 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, break; default: - DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); + dev_dbg(info->device, + "Unsupported bpp size: %d\n", var->bits_per_pixel); assert(false); /* should never occur */ break; } + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + /* use highest possible virtual resolution */ + if (var->yres_virtual == -1) { + var->yres_virtual = pixels / var->xres_virtual; + + dev_info(info->device, + "virtual resolution set to maximum of %dx%d\n", + var->xres_virtual, var->yres_virtual); + } + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xres_virtual * var->yres_virtual > pixels) { + dev_err(info->device, "mode %dx%dx%d rejected... " + "virtual resolution too high to fit into video memory!\n", + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + return -EINVAL; + } + + if (var->xoffset < 0) + var->xoffset = 0; + if (var->yoffset < 0) + var->yoffset = 0; + + /* truncate xoffset and yoffset to maximum if too high */ + if (var->xoffset > var->xres_virtual - var->xres) + var->xoffset = var->xres_virtual - var->xres - 1; + if (var->yoffset > var->yres_virtual - var->yres) + var->yoffset = var->yres_virtual - var->yres - 1; + var->red.msb_right = var->green.msb_right = var->blue.msb_right = @@ -606,99 +618,31 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, yres = (yres + 1) / 2; if (yres >= 1280) { - printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; " + dev_err(info->device, "ERROR: VerticalTotal >= 1280; " "special treatment required! (TODO)\n"); - DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } - return 0; -} - -static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, - struct cirrusfb_regs *regs, - struct fb_info *info) -{ - long freq; - long maxclock; - int maxclockidx = var->bits_per_pixel >> 3; - struct cirrusfb_info *cinfo = info->par; - - switch (var->bits_per_pixel) { - case 1: - info->fix.line_length = var->xres_virtual / 8; - info->fix.visual = FB_VISUAL_MONO10; - break; - - case 8: - info->fix.line_length = var->xres_virtual; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - - case 16: - case 32: - info->fix.line_length = var->xres_virtual * maxclockidx; - info->fix.visual = FB_VISUAL_TRUECOLOR; - break; - - default: - DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); - assert(false); - /* should never occur */ - break; - } - - info->fix.type = FB_TYPE_PACKED_PIXELS; - - /* convert from ps to kHz */ - freq = PICOS2KHZ(var->pixclock); - - DPRINTK("desired pixclock: %ld kHz\n", freq); - - maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; - regs->multiplexing = 0; + if (cirrusfb_check_pixclock(var, info)) + return -EINVAL; - /* If the frequency is greater than we can support, we might be able - * to use multiplexing for the video mode */ - if (freq > maxclock) { - switch (cinfo->btype) { - case BT_ALPINE: - case BT_GD5480: - regs->multiplexing = 1; - break; + if (!is_laguna(cinfo)) + var->accel_flags = FB_ACCELF_TEXT; - default: - printk(KERN_ERR "cirrusfb: Frequency greater " - "than maxclock (%ld kHz)\n", maxclock); - DPRINTK("EXIT - return -EINVAL\n"); - return -EINVAL; - } - } -#if 0 - /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where - * the VCLK is double the pixel clock. */ - switch (var->bits_per_pixel) { - case 16: - case 32: - if (var->xres <= 800) - /* Xbh has this type of clock for 32-bit */ - freq /= 2; - break; - } -#endif return 0; } -static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo, - int div) +static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div) { + struct cirrusfb_info *cinfo = info->par; unsigned char old1f, old1e; + assert(cinfo != NULL); old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40; if (div) { - DPRINTK("Set %s as pixclock source.\n", - (div == 2) ? "MCLK/2" : "MCLK"); + dev_dbg(info->device, "Set %s as pixclock source.\n", + (div == 2) ? "MCLK/2" : "MCLK"); old1f |= 0x40; old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1; if (div == 2) @@ -718,101 +662,119 @@ static int cirrusfb_set_par_foo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; - struct cirrusfb_regs regs; u8 __iomem *regbase = cinfo->regbase; unsigned char tmp; - int offset = 0, err; + int pitch; const struct cirrusfb_board_info_rec *bi; int hdispend, hsyncstart, hsyncend, htotal; int yres, vdispend, vsyncstart, vsyncend, vtotal; long freq; int nom, den, div; + unsigned int control = 0, format = 0, threshold = 0; - DPRINTK("ENTER\n"); - DPRINTK("Requested mode: %dx%dx%d\n", + dev_dbg(info->device, "Requested mode: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK("pixclock: %d\n", var->pixclock); - init_vgachip(info); + switch (var->bits_per_pixel) { + case 1: + info->fix.line_length = var->xres_virtual / 8; + info->fix.visual = FB_VISUAL_MONO10; + break; - err = cirrusfb_decode_var(var, ®s, info); - if (err) { - /* should never happen */ - DPRINTK("mode change aborted. invalid var.\n"); - return -EINVAL; + case 8: + info->fix.line_length = var->xres_virtual; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + case 24: + info->fix.line_length = var->xres_virtual * + var->bits_per_pixel >> 3; + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; } + info->fix.type = FB_TYPE_PACKED_PIXELS; + + init_vgachip(info); bi = &cirrusfb_board_info[cinfo->btype]; hsyncstart = var->xres + var->right_margin; hsyncend = hsyncstart + var->hsync_len; - htotal = (hsyncend + var->left_margin) / 8 - 5; - hdispend = var->xres / 8 - 1; - hsyncstart = hsyncstart / 8 + 1; - hsyncend = hsyncend / 8 + 1; + htotal = (hsyncend + var->left_margin) / 8; + hdispend = var->xres / 8; + hsyncstart = hsyncstart / 8; + hsyncend = hsyncend / 8; - yres = var->yres; - vsyncstart = yres + var->lower_margin; + vdispend = var->yres; + vsyncstart = vdispend + var->lower_margin; vsyncend = vsyncstart + var->vsync_len; vtotal = vsyncend + var->upper_margin; - vdispend = yres - 1; if (var->vmode & FB_VMODE_DOUBLE) { - yres *= 2; + vdispend *= 2; vsyncstart *= 2; vsyncend *= 2; vtotal *= 2; } else if (var->vmode & FB_VMODE_INTERLACED) { - yres = (yres + 1) / 2; + vdispend = (vdispend + 1) / 2; vsyncstart = (vsyncstart + 1) / 2; vsyncend = (vsyncend + 1) / 2; vtotal = (vtotal + 1) / 2; } - - vtotal -= 2; - vsyncstart -= 1; - vsyncend -= 1; - + yres = vdispend; if (yres >= 1024) { vtotal /= 2; vsyncstart /= 2; vsyncend /= 2; vdispend /= 2; } - if (regs.multiplexing) { + + vdispend -= 1; + vsyncstart -= 1; + vsyncend -= 1; + vtotal -= 2; + + if (cinfo->multiplexing) { htotal /= 2; hsyncstart /= 2; hsyncend /= 2; hdispend /= 2; } + + htotal -= 5; + hdispend -= 1; + hsyncstart += 1; + hsyncend += 1; + /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ /* if debugging is enabled, all parameters get output before writing */ - DPRINTK("CRT0: %d\n", htotal); + dev_dbg(info->device, "CRT0: %d\n", htotal); vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal); - DPRINTK("CRT1: %d\n", hdispend); + dev_dbg(info->device, "CRT1: %d\n", hdispend); vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend); - DPRINTK("CRT2: %d\n", var->xres / 8); + dev_dbg(info->device, "CRT2: %d\n", var->xres / 8); vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8); /* + 128: Compatible read */ - DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32); + dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32); vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, 128 + ((htotal + 5) % 32)); - DPRINTK("CRT4: %d\n", hsyncstart); + dev_dbg(info->device, "CRT4: %d\n", hsyncstart); vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart); tmp = hsyncend % 32; if ((htotal + 5) & 32) tmp += 128; - DPRINTK("CRT5: %d\n", tmp); + dev_dbg(info->device, "CRT5: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); - DPRINTK("CRT6: %d\n", vtotal & 0xff); + dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff); tmp = 16; /* LineCompare bit #9 */ @@ -830,7 +792,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) tmp |= 64; if (vsyncstart & 512) tmp |= 128; - DPRINTK("CRT7: %d\n", tmp); + dev_dbg(info->device, "CRT7: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); tmp = 0x40; /* LineCompare bit #8 */ @@ -838,25 +800,25 @@ static int cirrusfb_set_par_foo(struct fb_info *info) tmp |= 0x20; if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; - DPRINTK("CRT9: %d\n", tmp); + dev_dbg(info->device, "CRT9: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); - DPRINTK("CRT10: %d\n", vsyncstart & 0xff); + dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff); vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff); - DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16); + dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16); vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32); - DPRINTK("CRT12: %d\n", vdispend & 0xff); + dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff); vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff); - DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff); + dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff); - DPRINTK("CRT16: %d\n", vtotal & 0xff); + dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff); - DPRINTK("CRT18: 0xff\n"); + dev_dbg(info->device, "CRT18: 0xff\n"); vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); tmp = 0; @@ -871,41 +833,75 @@ static int cirrusfb_set_par_foo(struct fb_info *info) if (vtotal & 512) tmp |= 128; - DPRINTK("CRT1a: %d\n", tmp); + dev_dbg(info->device, "CRT1a: %d\n", tmp); vga_wcrt(regbase, CL_CRT1A, tmp); freq = PICOS2KHZ(var->pixclock); + if (var->bits_per_pixel == 24) + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) + freq *= 3; + if (cinfo->multiplexing) + freq /= 2; + if (cinfo->doubleVCLK) + freq *= 2; + bestclock(freq, &nom, &den, &div); + dev_dbg(info->device, "VCLK freq: %ld kHz nom: %d den: %d div: %d\n", + freq, nom, den, div); + /* set VCLK0 */ /* hardware RefClock: 14.31818 MHz */ /* formula: VClk = (OSC * N) / (D * (1+P)) */ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ - if (cinfo->btype == BT_ALPINE) { + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 || + cinfo->btype == BT_SD64) { /* if freq is close to mclk or mclk/2 select mclk * as clock source */ - int divMCLK = cirrusfb_check_mclk(cinfo, freq); - if (divMCLK) { + int divMCLK = cirrusfb_check_mclk(info, freq); + if (divMCLK) nom = 0; - cirrusfb_set_mclk_as_source(cinfo, divMCLK); + cirrusfb_set_mclk_as_source(info, divMCLK); + } + if (is_laguna(cinfo)) { + long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc); + unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407); + unsigned short tile_control; + + if (cinfo->btype == BT_LAGUNAB) { + tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4); + tile_control &= ~0x80; + fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4); } + + fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc); + fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407); + control = fb_readw(cinfo->laguna_mmio + 0x402); + threshold = fb_readw(cinfo->laguna_mmio + 0xea); + control &= ~0x6800; + format = 0; + threshold &= 0xffc0 & 0x3fbf; } if (nom) { - vga_wseq(regbase, CL_SEQRB, nom); tmp = den << 1; if (div != 0) tmp |= 1; - /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ if ((cinfo->btype == BT_SD64) || (cinfo->btype == BT_ALPINE) || (cinfo->btype == BT_GD5480)) tmp |= 0x80; - DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); - vga_wseq(regbase, CL_SEQR1B, tmp); + /* Laguna chipset has reversed clock registers */ + if (is_laguna(cinfo)) { + vga_wseq(regbase, CL_SEQRE, tmp); + vga_wseq(regbase, CL_SEQR1E, nom); + } else { + vga_wseq(regbase, CL_SEQRE, nom); + vga_wseq(regbase, CL_SEQR1E, tmp); + } } if (yres >= 1024) @@ -916,9 +912,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) * address wrap, no compat. */ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); -/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); - * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ - /* don't know if it would hurt to also program this if no interlaced */ /* mode is used, but I feel better this way.. :-) */ if (var->vmode & FB_VMODE_INTERLACED) @@ -926,19 +919,15 @@ static int cirrusfb_set_par_foo(struct fb_info *info) else vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ - vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); - - /* adjust horizontal/vertical sync type (low/high) */ + /* adjust horizontal/vertical sync type (low/high), use VCLK3 */ /* enable display memory & CRTC I/O address for color mode */ - tmp = 0x03; + tmp = 0x03 | 0xc; if (var->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80; WGen(cinfo, VGA_MIS_W, tmp); - /* Screen A Preset Row-Scan register */ - vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); /* text cursor on and start line */ vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor end line */ @@ -952,7 +941,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) /* programming for different color depths */ if (var->bits_per_pixel == 1) { - DPRINTK("cirrusfb: preparing for 1 bit deep display\n"); + dev_dbg(info->device, "preparing for 1 bit deep display\n"); vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */ /* SR07 */ @@ -964,68 +953,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK(" (for GD54xx)\n"); vga_wseq(regbase, CL_SEQR7, - regs.multiplexing ? + cinfo->multiplexing ? bi->sr07_1bpp_mux : bi->sr07_1bpp); break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* Extended Sequencer Mode */ switch (cinfo->btype) { - case BT_SD64: - /* setting the SEQRF on SD64 is not necessary - * (only during init) - */ - DPRINTK("(for SD64)\n"); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1a); - break; case BT_PICCOLO: case BT_SPECTRUM: - DPRINTK("(for Piccolo/Spectrum)\n"); - /* ### ueberall 0x22? */ - /* ##vorher 1c MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ vga_wseq(regbase, CL_SEQRF, 0xb0); break; case BT_PICASSO: - DPRINTK("(for Picasso)\n"); - /* ##vorher 22 MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* ## vorher d0 avoid FIFO underruns..? */ vga_wseq(regbase, CL_SEQRF, 0xd0); break; + case BT_SD64: case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: case BT_LAGUNA: - DPRINTK(" (for GD54xx)\n"); + case BT_LAGUNAB: /* do nothing */ break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* pixel mask: pass-through for first plane */ WGen(cinfo, VGA_PEL_MSK, 0x01); - if (regs.multiplexing) + if (cinfo->multiplexing) /* hidden dac reg: 1280x1024 */ WHDR(cinfo, 0x4a); else @@ -1035,7 +1009,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* plane mask: only write to first plane */ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01); - offset = var->xres_virtual / 16; } /****************************************************** @@ -1045,7 +1018,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else if (var->bits_per_pixel == 8) { - DPRINTK("cirrusfb: preparing for 8 bit deep display\n"); + dev_dbg(info->device, "preparing for 8 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: case BT_PICCOLO: @@ -1054,34 +1027,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK(" (for GD54xx)\n"); vga_wseq(regbase, CL_SEQR7, - regs.multiplexing ? + cinfo->multiplexing ? bi->sr07_8bpp_mux : bi->sr07_8bpp); break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) | 0x01); + threshold |= 0x10; break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } switch (cinfo->btype) { - case BT_SD64: - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1d); - break; - case BT_PICCOLO: case BT_PICASSO: case BT_SPECTRUM: - /* ### vorher 1c MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); break; @@ -1091,40 +1057,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info) /* ### INCOMPLETE!! */ vga_wseq(regbase, CL_SEQRF, 0xb8); #endif -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - /* We already set SRF and SR1F */ - break; - + case BT_SD64: case BT_GD5480: case BT_LAGUNA: - DPRINTK(" (for GD54xx)\n"); + case BT_LAGUNAB: /* do nothing */ break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); - if (regs.multiplexing) + if (cinfo->multiplexing) /* hidden dac reg: 1280x1024 */ WHDR(cinfo, 0x4a); else /* hidden dac: nothing */ WHDR(cinfo, 0); - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 8; } /****************************************************** @@ -1134,147 +1087,110 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else if (var->bits_per_pixel == 16) { - DPRINTK("cirrusfb: preparing for 16 bit deep display\n"); + dev_dbg(info->device, "preparing for 16 bit deep display\n"); switch (cinfo->btype) { - case BT_SD64: - /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq(regbase, CL_SEQR7, 0xf7); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1e); - break; - case BT_PICCOLO: case BT_SPECTRUM: vga_wseq(regbase, CL_SEQR7, 0x87); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: vga_wseq(regbase, CL_SEQR7, 0x27); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; + case BT_SD64: case BT_PICASSO4: - vga_wseq(regbase, CL_SEQR7, 0x27); -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - vga_wseq(regbase, CL_SEQR7, 0xa7); + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, + cinfo->doubleVCLK ? 0xa3 : 0xa7); break; case BT_GD5480: - DPRINTK(" (for GD5480)\n"); vga_wseq(regbase, CL_SEQR7, 0x17); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); + control |= 0x2000; + format |= 0x1400; + threshold |= 0x10; break; default: - printk(KERN_WARNING "CIRRUSFB: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); #ifdef CONFIG_PCI - WHDR(cinfo, 0xc0); /* Copy Xbh */ + WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1); #elif defined(CONFIG_ZORRO) /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */ #endif - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 4; } /****************************************************** * - * 32 bpp + * 24 bpp * */ - else if (var->bits_per_pixel == 32) { - DPRINTK("cirrusfb: preparing for 32 bit deep display\n"); + else if (var->bits_per_pixel == 24) { + dev_dbg(info->device, "preparing for 24 bit deep display\n"); switch (cinfo->btype) { - case BT_SD64: - /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq(regbase, CL_SEQR7, 0xf9); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1e); - break; - case BT_PICCOLO: case BT_SPECTRUM: vga_wseq(regbase, CL_SEQR7, 0x85); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: vga_wseq(regbase, CL_SEQR7, 0x25); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; + case BT_SD64: case BT_PICASSO4: - vga_wseq(regbase, CL_SEQR7, 0x25); -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - vga_wseq(regbase, CL_SEQR7, 0xa9); + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, 0xa5); break; case BT_GD5480: - DPRINTK(" (for GD5480)\n"); - vga_wseq(regbase, CL_SEQR7, 0x19); + vga_wseq(regbase, CL_SEQR7, 0x15); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); + control |= 0x4000; + format |= 0x2400; + threshold |= 0x20; break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); /* hidden dac reg: 8-8-8 mode (24 or 32) */ WHDR(cinfo, 0xc5); - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 4; } /****************************************************** @@ -1284,67 +1200,55 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else - printk(KERN_ERR "cirrusfb: What's this?? " - " requested color depth == %d.\n", + dev_err(info->device, + "What's this? requested color depth == %d.\n", var->bits_per_pixel); - vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff); + pitch = info->fix.line_length >> 3; + vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff); tmp = 0x22; - if (offset & 0x100) + if (pitch & 0x100) tmp |= 0x10; /* offset overflow bit */ /* screen start addr #16-18, fastpagemode cycles */ vga_wcrt(regbase, CL_CRT1B, tmp); - if (cinfo->btype == BT_SD64 || - cinfo->btype == BT_PICASSO4 || - cinfo->btype == BT_ALPINE || - cinfo->btype == BT_GD5480) - /* screen start address bit 19 */ - vga_wcrt(regbase, CL_CRT1D, 0x00); - - /* text cursor location high */ - vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0); - /* text cursor location low */ - vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0); - /* underline row scanline = at very bottom */ - vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0); - - /* controller mode */ - vga_wattr(regbase, VGA_ATC_MODE, 1); - /* overscan (border) color */ - vga_wattr(regbase, VGA_ATC_OVERSCAN, 0); - /* color plane enable */ - vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15); + /* screen start address bit 19 */ + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) + vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1); + + if (is_laguna(cinfo)) { + tmp = 0; + if ((htotal + 5) & 256) + tmp |= 128; + if (hdispend & 256) + tmp |= 64; + if (hsyncstart & 256) + tmp |= 48; + if (vtotal & 1024) + tmp |= 8; + if (vdispend & 1024) + tmp |= 4; + if (vsyncstart & 1024) + tmp |= 3; + + vga_wcrt(regbase, CL_CRT1E, tmp); + dev_dbg(info->device, "CRT1e: %d\n", tmp); + } + /* pixel panning */ vga_wattr(regbase, CL_AR33, 0); - /* color select */ - vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0); /* [ EGS: SetOffset(); ] */ /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ AttrOn(cinfo); - /* set/reset register */ - vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0); - /* set/reset enable */ - vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0); - /* color compare */ - vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0); - /* data rotate */ - vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0); - /* read map select */ - vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0); - /* miscellaneous register */ - vga_wgfx(regbase, VGA_GFX_MISC, 1); - /* color don't care */ - vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15); - /* bit mask */ - vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255); - - /* graphics cursor attributes: nothing special */ - vga_wseq(regbase, CL_SEQR12, 0x0); - + if (is_laguna(cinfo)) { + /* no tiles */ + fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402); + fb_writew(format, cinfo->laguna_mmio + 0xc0); + fb_writew(threshold, cinfo->laguna_mmio + 0xea); + } /* finally, turn on everything - turn off "FullBandwidth" bit */ /* also, set "DotClock%2" bit where requested */ tmp = 0x01; @@ -1355,18 +1259,12 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); - DPRINTK("CL_SEQR1: %d\n", tmp); - - cinfo->currentmode = regs; - - /* pan to requested offset */ - cirrusfb_pan_display(var, info); + dev_dbg(info->device, "CL_SEQR1: %d\n", tmp); #ifdef CIRRUSFB_DEBUG - cirrusfb_dump(); + cirrusfb_dbg_reg_dump(info, NULL); #endif - DPRINTK("EXIT\n"); return 0; } @@ -1418,27 +1316,19 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int cirrusfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - int xoffset = 0; - int yoffset = 0; + int xoffset; unsigned long base; - unsigned char tmp = 0, tmp2 = 0, xpix; + unsigned char tmp, xpix; struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); - DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); - /* no range checks for xoffset and yoffset, */ /* as fb_pan_display has already done this */ if (var->vmode & FB_VMODE_YWRAP) return -EINVAL; - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - xoffset = var->xoffset * info->var.bits_per_pixel / 8; - yoffset = var->yoffset; - base = yoffset * info->fix.line_length + xoffset; + base = var->yoffset * info->fix.line_length + xoffset; if (info->var.bits_per_pixel == 1) { /* base is already correct */ @@ -1448,14 +1338,15 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, xpix = (unsigned char) ((xoffset % 4) * 2); } - cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ + if (!is_laguna(cinfo)) + cirrusfb_WaitBLT(cinfo->regbase); /* lower 8 + 8 bits of screen start address */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, - (unsigned char) (base & 0xff)); - vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, - (unsigned char) (base >> 8)); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff); + /* 0xf2 is %11110010, exclude tmp bits */ + tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2; /* construct bits 16, 17 and 18 of screen start address */ if (base & 0x10000) tmp |= 0x01; @@ -1464,13 +1355,17 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, if (base & 0x40000) tmp |= 0x08; - /* 0xf2 is %11110010, exclude tmp bits */ - tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; - vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2); + vga_wcrt(cinfo->regbase, CL_CRT1B, tmp); /* construct bit 19 of screen start address */ - if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) - vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80); + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) { + tmp = vga_rcrt(cinfo->regbase, CL_CRT1D); + if (is_laguna(cinfo)) + tmp = (tmp & ~0x18) | ((base >> 16) & 0x18); + else + tmp = (tmp & ~0x80) | ((base >> 12) & 0x80); + vga_wcrt(cinfo->regbase, CL_CRT1D, tmp); + } /* write pixel panning value to AR33; this does not quite work in 8bpp * @@ -1479,9 +1374,6 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, if (info->var.bits_per_pixel == 1) vga_wattr(cinfo->regbase, CL_AR33, xpix); - cirrusfb_WaitBLT(cinfo->regbase); - - DPRINTK("EXIT\n"); return 0; } @@ -1502,57 +1394,54 @@ static int cirrusfb_blank(int blank_mode, struct fb_info *info) struct cirrusfb_info *cinfo = info->par; int current_mode = cinfo->blank_mode; - DPRINTK("ENTER, blank mode = %d\n", blank_mode); + dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode); if (info->state != FBINFO_STATE_RUNNING || current_mode == blank_mode) { - DPRINTK("EXIT, returning 0\n"); + dev_dbg(info->device, "EXIT, returning 0\n"); return 0; } /* Undo current */ if (current_mode == FB_BLANK_NORMAL || - current_mode == FB_BLANK_UNBLANK) { - /* unblank the screen */ - val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + current_mode == FB_BLANK_UNBLANK) /* clear "FullBandwidth" bit */ - vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); - /* and undo VESA suspend trickery */ - vga_wgfx(cinfo->regbase, CL_GRE, 0x00); - } - - /* set new */ - if (blank_mode > FB_BLANK_NORMAL) { - /* blank the screen */ - val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + val = 0; + else /* set "FullBandwidth" bit */ - vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); - } + val = 0x20; + + val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf; + vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val); switch (blank_mode) { case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: + val = 0x00; break; case FB_BLANK_VSYNC_SUSPEND: - vga_wgfx(cinfo->regbase, CL_GRE, 0x04); + val = 0x04; break; case FB_BLANK_HSYNC_SUSPEND: - vga_wgfx(cinfo->regbase, CL_GRE, 0x02); + val = 0x02; break; case FB_BLANK_POWERDOWN: - vga_wgfx(cinfo->regbase, CL_GRE, 0x06); + val = 0x06; break; default: - DPRINTK("EXIT, returning 1\n"); + dev_dbg(info->device, "EXIT, returning 1\n"); return 1; } + vga_wgfx(cinfo->regbase, CL_GRE, val); + cinfo->blank_mode = blank_mode; - DPRINTK("EXIT, returning 0\n"); + dev_dbg(info->device, "EXIT, returning 0\n"); /* Let fbcon do a soft blank for us */ return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; } + /**** END Hardware specific Routines **************************************/ /****************************************************************************/ /**** BEGIN Internal Routines ***********************************************/ @@ -1562,8 +1451,6 @@ static void init_vgachip(struct fb_info *info) struct cirrusfb_info *cinfo = info->par; const struct cirrusfb_board_info_rec *bi; - DPRINTK("ENTER\n"); - assert(cinfo != NULL); bi = &cirrusfb_board_info[cinfo->btype]; @@ -1591,25 +1478,23 @@ static void init_vgachip(struct fb_info *info) /* disable flickerfixer */ vga_wcrt(cinfo->regbase, CL_CRT51, 0x00); mdelay(100); - /* from Klaus' NetBSD driver: */ - vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); - /* put blitter into 542x compat */ - vga_wgfx(cinfo->regbase, CL_GR33, 0x00); /* mode */ vga_wgfx(cinfo->regbase, CL_GR31, 0x00); - break; - - case BT_GD5480: + case BT_GD5480: /* fall through */ /* from Klaus' NetBSD driver: */ vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); + case BT_ALPINE: /* fall through */ + /* put blitter into 542x compat */ + vga_wgfx(cinfo->regbase, CL_GR33, 0x00); break; - case BT_ALPINE: + case BT_LAGUNA: + case BT_LAGUNAB: /* Nothing to do to reset the board. */ break; default: - printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n"); + dev_err(info->device, "Warning: Unknown board type\n"); break; } @@ -1629,31 +1514,28 @@ static void init_vgachip(struct fb_info *info) WGen(cinfo, CL_VSSM2, 0x01); /* reset sequencer logic */ - vga_wseq(cinfo->regbase, CL_SEQR0, 0x03); + vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03); /* FullBandwidth (video off) and 8/9 dot clock */ vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); - /* polarity (-/-), disable access to display memory, - * VGA_CRTC_START_HI base address: color - */ - WGen(cinfo, VGA_MIS_W, 0xc1); /* "magic cookie" - doesn't make any sense to me.. */ /* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ /* unlock all extension registers */ vga_wseq(cinfo->regbase, CL_SEQR6, 0x12); - /* reset blitter */ - vga_wgfx(cinfo->regbase, CL_GR31, 0x04); - switch (cinfo->btype) { case BT_GD5480: vga_wseq(cinfo->regbase, CL_SEQRF, 0x98); break; case BT_ALPINE: + case BT_LAGUNA: + case BT_LAGUNAB: break; case BT_SD64: +#ifdef CONFIG_ZORRO vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8); +#endif break; default: vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f); @@ -1665,8 +1547,8 @@ static void init_vgachip(struct fb_info *info) vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* character map select: doesn't even matter in gx mode */ vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); - /* memory mode: chain-4, no odd/even, ext. memory */ - vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); + /* memory mode: chain4, ext. memory */ + vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* controller-internal base address of video memory */ if (bi->init_sr07) @@ -1692,20 +1574,12 @@ static void init_vgachip(struct fb_info *info) vga_wseq(cinfo->regbase, CL_SEQR18, 0x02); } - /* MCLK select etc. */ - if (bi->init_sr1f) - vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f); - /* Screen A preset row scan: none */ vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Text cursor start: disable text cursor */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor end: - */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); - /* Screen start address high: 0 */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00); - /* Screen start address low: 0 */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* text cursor location high: 0 */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location low: 0 */ @@ -1713,10 +1587,6 @@ static void init_vgachip(struct fb_info *info) /* Underline Row scanline: - */ vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); - /* mode control: timing enable, byte mode, no compat modes */ - vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3); - /* Line Compare: not needed */ - vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* ### add 0x40 for text modes with > 30 MHz pixclock */ /* ext. display controls: ext.adr. wrap */ vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); @@ -1739,7 +1609,9 @@ static void init_vgachip(struct fb_info *info) vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Bit Mask: no mask at all */ vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); - if (cinfo->btype == BT_ALPINE) + + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 || + is_laguna(cinfo)) /* (5434 can't have bit 3 set for bitblt) */ vga_wgfx(cinfo->regbase, CL_GRB, 0x20); else @@ -1779,18 +1651,11 @@ static void init_vgachip(struct fb_info *info) vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Color Plane enable: Enable all 4 planes */ vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); -/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ /* Color Select: - */ vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ - if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) - /* polarity (-/-), enable display mem, - * VGA_CRTC_START_HI i/o base = color - */ - WGen(cinfo, VGA_MIS_W, 0xc3); - /* BLT Start/status: Blitter reset */ vga_wgfx(cinfo->regbase, CL_GR31, 0x04); /* - " - : "end-of-reset" */ @@ -1798,8 +1663,6 @@ static void init_vgachip(struct fb_info *info) /* misc... */ WHDR(cinfo, 0); /* Hidden DAC register: - */ - - DPRINTK("EXIT\n"); return; } @@ -1808,8 +1671,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) #ifdef CONFIG_ZORRO /* only works on Zorro boards */ static int IsOn = 0; /* XXX not ok for multiple boards */ - DPRINTK("ENTER\n"); - if (cinfo->btype == BT_PICASSO4) return; /* nothing to switch */ if (cinfo->btype == BT_ALPINE) @@ -1819,8 +1680,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) if (cinfo->btype == BT_PICASSO) { if ((on && !IsOn) || (!on && IsOn)) WSFR(cinfo, 0xff); - - DPRINTK("EXIT\n"); return; } if (on) { @@ -1847,11 +1706,10 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) case BT_SPECTRUM: WSFR(cinfo, 0x4f); break; - default: /* do nothing */ break; + default: /* do nothing */ + break; } } - - DPRINTK("EXIT\n"); #endif /* CONFIG_ZORRO */ } @@ -1859,6 +1717,17 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) /* Linux 2.6-style accelerated functions */ /******************************************/ +static int cirrusfb_sync(struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + + if (!is_laguna(cinfo)) { + while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03) + cpu_relax(); + } + return 0; +} + static void cirrusfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) { @@ -1894,8 +1763,8 @@ static void cirrusfb_fillrect(struct fb_info *info, info->var.bits_per_pixel, (region->dx * m) / 8, region->dy, (region->width * m) / 8, region->height, - color, - info->fix.line_length); + color, color, + info->fix.line_length, 0x40); } static void cirrusfb_copyarea(struct fb_info *info, @@ -1943,9 +1812,46 @@ static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct cirrusfb_info *cinfo = info->par; + unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4; - cirrusfb_WaitBLT(cinfo->regbase); - cfb_imageblit(info, image); + if (info->state != FBINFO_STATE_RUNNING) + return; + /* Alpine/SD64 does not work at 24bpp ??? */ + if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) + cfb_imageblit(info, image); + else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) && + op == 0xc) + cfb_imageblit(info, image); + else { + unsigned size = ((image->width + 7) >> 3) * image->height; + int m = info->var.bits_per_pixel; + u32 fg, bg; + + if (info->var.bits_per_pixel == 8) { + fg = image->fg_color; + bg = image->bg_color; + } else { + fg = ((u32 *)(info->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(info->pseudo_palette))[image->bg_color]; + } + if (info->var.bits_per_pixel == 24) { + /* clear background first */ + cirrusfb_RectFill(cinfo->regbase, + info->var.bits_per_pixel, + (image->dx * m) / 8, image->dy, + (image->width * m) / 8, + image->height, + bg, bg, + info->fix.line_length, 0x40); + } + cirrusfb_RectFill(cinfo->regbase, + info->var.bits_per_pixel, + (image->dx * m) / 8, image->dy, + (image->width * m) / 8, image->height, + fg, bg, + info->fix.line_length, op); + memcpy(info->screen_base, image->data, size); + } } #ifdef CONFIG_PPC_PREP @@ -1953,12 +1859,8 @@ static void cirrusfb_imageblit(struct fb_info *info, #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) static void get_prep_addrs(unsigned long *display, unsigned long *registers) { - DPRINTK("ENTER\n"); - *display = PREP_VIDEO_BASE; *registers = (unsigned long) PREP_IO_BASE; - - DPRINTK("EXIT\n"); } #endif /* CONFIG_PPC_PREP */ @@ -1970,40 +1872,43 @@ static int release_io_ports; * based on the DRAM bandwidth bit and DRAM bank switching bit. This * works with 1MB, 2MB and 4MB configurations (which the Motorola boards * seem to have. */ -static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase) +static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info, + u8 __iomem *regbase) { unsigned long mem; - unsigned char SRF; + struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); + if (is_laguna(cinfo)) { + unsigned char SR14 = vga_rseq(regbase, CL_SEQR14); - SRF = vga_rseq(regbase, CL_SEQRF); - switch ((SRF & 0x18)) { - case 0x08: - mem = 512 * 1024; - break; - case 0x10: - mem = 1024 * 1024; - break; - /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory - * on the 5430. - */ - case 0x18: - mem = 2048 * 1024; - break; - default: - printk(KERN_WARNING "CLgenfb: Unknown memory size!\n"); - mem = 1024 * 1024; + mem = ((SR14 & 7) + 1) << 20; + } else { + unsigned char SRF = vga_rseq(regbase, CL_SEQRF); + switch ((SRF & 0x18)) { + case 0x08: + mem = 512 * 1024; + break; + case 0x10: + mem = 1024 * 1024; + break; + /* 64-bit DRAM data bus width; assume 2MB. + * Also indicates 2MB memory on the 5430. + */ + case 0x18: + mem = 2048 * 1024; + break; + default: + dev_warn(info->device, "Unknown memory size!\n"); + mem = 1024 * 1024; + } + /* If DRAM bank switching is enabled, there must be + * twice as much memory installed. (4MB on the 5434) + */ + if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0) + mem *= 2; } - if (SRF & 0x80) - /* If DRAM bank switching is enabled, there must be twice as much - * memory installed. (4MB on the 5434) - */ - mem *= 2; /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ - - DPRINTK("EXIT\n"); return mem; } @@ -2014,8 +1919,6 @@ static void get_pci_addrs(const struct pci_dev *pdev, assert(display != NULL); assert(registers != NULL); - DPRINTK("ENTER\n"); - *display = 0; *registers = 0; @@ -2030,14 +1933,15 @@ static void get_pci_addrs(const struct pci_dev *pdev, } assert(*display != 0); - - DPRINTK("EXIT\n"); } static void cirrusfb_pci_unmap(struct fb_info *info) { struct pci_dev *pdev = to_pci_dev(info->device); + struct cirrusfb_info *cinfo = info->par; + if (cinfo->laguna_mmio == NULL) + iounmap(cinfo->laguna_mmio); iounmap(info->screen_base); #if 0 /* if system didn't claim this region, we would... */ release_mem_region(0xA0000, 65535); @@ -2067,6 +1971,22 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) } #endif /* CONFIG_ZORRO */ +/* function table of the above functions */ +static struct fb_ops cirrusfb_ops = { + .owner = THIS_MODULE, + .fb_open = cirrusfb_open, + .fb_release = cirrusfb_release, + .fb_setcolreg = cirrusfb_setcolreg, + .fb_check_var = cirrusfb_check_var, + .fb_set_par = cirrusfb_set_par, + .fb_pan_display = cirrusfb_pan_display, + .fb_blank = cirrusfb_blank, + .fb_fillrect = cirrusfb_fillrect, + .fb_copyarea = cirrusfb_copyarea, + .fb_sync = cirrusfb_sync, + .fb_imageblit = cirrusfb_imageblit, +}; + static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; @@ -2077,10 +1997,16 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA; - if (noaccel) + if (noaccel || is_laguna(cinfo)) { info->flags |= FBINFO_HWACCEL_DISABLED; + info->fix.accel = FB_ACCEL_NONE; + } else + info->fix.accel = FB_ACCEL_CIRRUS_ALPINE; + info->fbops = &cirrusfb_ops; + if (cinfo->btype == BT_GD5480) { if (var->bits_per_pixel == 16) info->screen_base += 1 * MB_; @@ -2104,7 +2030,6 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) /* FIXME: map region at 0xB8000 if available, fill in here */ info->fix.mmio_len = 0; - info->fix.accel = FB_ACCEL_NONE; fb_alloc_cmap(&info->cmap, 256, 0); @@ -2115,70 +2040,56 @@ static int __devinit cirrusfb_register(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; int err; - enum cirrus_board btype; - - DPRINTK("ENTER\n"); - - printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based " - "graphic boards, v" CIRRUSFB_VERSION "\n"); - - btype = cinfo->btype; /* sanity checks */ - assert(btype != BT_NONE); + assert(cinfo->btype != BT_NONE); /* set all the vital stuff */ cirrusfb_set_fbinfo(info); - DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base); + dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base); err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err) { - DPRINTK("wrong initial video mode\n"); + dev_dbg(info->device, "wrong initial video mode\n"); err = -EINVAL; goto err_dealloc_cmap; } info->var.activate = FB_ACTIVATE_NOW; - err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info); + err = cirrusfb_check_var(&info->var, info); if (err < 0) { /* should never happen */ - DPRINTK("choking on default var... umm, no good.\n"); + dev_dbg(info->device, + "choking on default var... umm, no good.\n"); goto err_dealloc_cmap; } err = register_framebuffer(info); if (err < 0) { - printk(KERN_ERR "cirrusfb: could not register " - "fb device; err = %d!\n", err); + dev_err(info->device, + "could not register fb device; err = %d!\n", err); goto err_dealloc_cmap; } - DPRINTK("EXIT, returning 0\n"); return 0; err_dealloc_cmap: fb_dealloc_cmap(&info->cmap); - cinfo->unmap(info); - framebuffer_release(info); return err; } static void __devexit cirrusfb_cleanup(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); switch_monitor(cinfo, 0); - unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - printk("Framebuffer unregistered\n"); + dev_dbg(info->device, "Framebuffer unregistered\n"); cinfo->unmap(info); framebuffer_release(info); - - DPRINTK("EXIT\n"); } #ifdef CONFIG_PCI @@ -2187,7 +2098,6 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, { struct cirrusfb_info *cinfo; struct fb_info *info; - enum cirrus_board btype; unsigned long board_addr, board_size; int ret; @@ -2201,15 +2111,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, if (!info) { printk(KERN_ERR "cirrusfb: could not allocate memory\n"); ret = -ENOMEM; - goto err_disable; + goto err_out; } cinfo = info->par; - cinfo->btype = btype = (enum cirrus_board) ent->driver_data; + cinfo->btype = (enum cirrus_board) ent->driver_data; - DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n", - pdev->resource[0].start, btype); - DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start); + dev_dbg(info->device, + " Found PCI device, base address 0 is 0x%Lx, btype set to %d\n", + (unsigned long long)pdev->resource[0].start, cinfo->btype); + dev_dbg(info->device, " base address 1 is 0x%Lx\n", + (unsigned long long)pdev->resource[1].start); if (isPReP) { pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000); @@ -2219,30 +2131,30 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, /* PReP dies if we ioremap the IO registers, but it works w/out... */ cinfo->regbase = (char __iomem *) info->fix.mmio_start; } else { - DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n"); + dev_dbg(info->device, + "Attempt to get PCI info for Cirrus Graphics Card\n"); get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start); /* FIXME: this forces VGA. alternatives? */ cinfo->regbase = NULL; + cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000); } - DPRINTK("Board address: 0x%lx, register address: 0x%lx\n", + dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fix.mmio_start); - board_size = (btype == BT_GD5480) ? - 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase); + board_size = (cinfo->btype == BT_GD5480) ? + 32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase); ret = pci_request_regions(pdev, "cirrusfb"); if (ret < 0) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " - "abort\n", - board_addr); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + board_addr); goto err_release_fb; } #if 0 /* if the system didn't claim this region, we would... */ if (!request_mem_region(0xA0000, 65535, "cirrusfb")) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n" -, - 0xA0000L); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + 0xA0000L); ret = -EBUSY; goto err_release_regions; } @@ -2260,16 +2172,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, info->screen_size = board_size; cinfo->unmap = cirrusfb_pci_unmap; - printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus " - "Logic chipset on PCI bus\n", - info->screen_size >> 10, board_addr); + dev_info(info->device, + "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n", + info->screen_size >> 10, board_addr); pci_set_drvdata(pdev, info); ret = cirrusfb_register(info); - if (ret) - iounmap(info->screen_base); - return ret; + if (!ret) + return 0; + pci_set_drvdata(pdev, NULL); + iounmap(info->screen_base); err_release_legacy: if (release_io_ports) release_region(0x3C0, 32); @@ -2279,8 +2192,9 @@ err_release_regions: #endif pci_release_regions(pdev); err_release_fb: + if (cinfo->laguna_mmio != NULL) + iounmap(cinfo->laguna_mmio); framebuffer_release(info); -err_disable: err_out: return ret; } @@ -2288,11 +2202,8 @@ err_out: static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - DPRINTK("ENTER\n"); cirrusfb_cleanup(info); - - DPRINTK("EXIT\n"); } static struct pci_driver cirrusfb_pci_driver = { @@ -2324,8 +2235,6 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (cirrusfb_zorro_table2[btype].id2) z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); size = cirrusfb_zorro_table2[btype].size; - printk(KERN_INFO "cirrusfb: %s board detected; ", - cirrusfb_board_info[btype].name); info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); if (!info) { @@ -2334,6 +2243,9 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, goto err_out; } + dev_info(info->device, "%s board detected\n", + cirrusfb_board_info[btype].name); + cinfo = info->par; cinfo->btype = btype; @@ -2345,19 +2257,16 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, info->screen_size = size; if (!zorro_request_device(z, "cirrusfb")) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " - "abort\n", - board_addr); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + board_addr); ret = -EBUSY; goto err_release_fb; } - printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); - ret = -EIO; if (btype == BT_PICASSO4) { - printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000); + dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); /* To be precise, for the P4 this is not the */ /* begin of the board, but the begin of RAM. */ @@ -2367,7 +2276,7 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (!cinfo->regbase) goto err_release_region; - DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + dev_dbg(info->device, "Virtual address for board set to: $%p\n", cinfo->regbase); cinfo->regbase += 0x600000; info->fix.mmio_start = board_addr + 0x600000; @@ -2377,8 +2286,8 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (!info->screen_base) goto err_unmap_regbase; } else { - printk(KERN_INFO " REG at $%lx\n", - (unsigned long) z2->resource.start); + dev_info(info->device, " REG at $%lx\n", + (unsigned long) z2->resource.start); info->fix.smem_start = board_addr; if (board_addr > 0x01000000) @@ -2392,27 +2301,32 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); info->fix.mmio_start = z2->resource.start; - DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + dev_dbg(info->device, "Virtual address for board set to: $%p\n", cinfo->regbase); } cinfo->unmap = cirrusfb_zorro_unmap; - printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); + dev_info(info->device, + "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", + board_size / MB_, board_addr); + zorro_set_drvdata(z, info); + /* MCLK select etc. */ + if (cirrusfb_board_info[btype].init_sr1f) + vga_wseq(cinfo->regbase, CL_SEQR1F, + cirrusfb_board_info[btype].sr1f); + ret = cirrusfb_register(info); - if (ret) { - if (btype == BT_PICASSO4) { - iounmap(info->screen_base); - iounmap(cinfo->regbase - 0x600000); - } else if (board_addr > 0x01000000) - iounmap(info->screen_base); - } - return ret; + if (!ret) + return 0; + + if (btype == BT_PICASSO4 || board_addr > 0x01000000) + iounmap(info->screen_base); err_unmap_regbase: - /* Parental advisory: explicit hack */ - iounmap(cinfo->regbase - 0x600000); + if (btype == BT_PICASSO4) + iounmap(cinfo->regbase - 0x600000); err_release_region: release_region(board_addr, board_size); err_release_fb: @@ -2424,11 +2338,8 @@ err_out: void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) { struct fb_info *info = zorro_get_drvdata(z); - DPRINTK("ENTER\n"); cirrusfb_cleanup(info); - - DPRINTK("EXIT\n"); } static struct zorro_driver cirrusfb_zorro_driver = { @@ -2439,33 +2350,11 @@ static struct zorro_driver cirrusfb_zorro_driver = { }; #endif /* CONFIG_ZORRO */ -static int __init cirrusfb_init(void) -{ - int error = 0; - #ifndef MODULE - char *option = NULL; - - if (fb_get_options("cirrusfb", &option)) - return -ENODEV; - cirrusfb_setup(option); -#endif - -#ifdef CONFIG_ZORRO - error |= zorro_register_driver(&cirrusfb_zorro_driver); -#endif -#ifdef CONFIG_PCI - error |= pci_register_driver(&cirrusfb_pci_driver); -#endif - return error; -} - -#ifndef MODULE -static int __init cirrusfb_setup(char *options) { +static int __init cirrusfb_setup(char *options) +{ char *this_opt; - DPRINTK("ENTER\n"); - if (!options || !*options) return 0; @@ -2473,8 +2362,6 @@ static int __init cirrusfb_setup(char *options) { if (!*this_opt) continue; - DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); - if (!strcmp(this_opt, "noaccel")) noaccel = 1; else if (!strncmp(this_opt, "mode:", 5)) @@ -2494,6 +2381,27 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>"); MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); MODULE_LICENSE("GPL"); +static int __init cirrusfb_init(void) +{ + int error = 0; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cirrusfb", &option)) + return -ENODEV; + cirrusfb_setup(option); +#endif + +#ifdef CONFIG_ZORRO + error |= zorro_register_driver(&cirrusfb_zorro_driver); +#endif +#ifdef CONFIG_PCI + error |= pci_register_driver(&cirrusfb_pci_driver); +#endif + return error; +} + static void __exit cirrusfb_exit(void) { #ifdef CONFIG_PCI @@ -2560,8 +2468,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo) { assert(cinfo != NULL); - DPRINTK("ENTER\n"); - if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) { /* if we're just in "write value" mode, write back the */ /* same value as before to not modify anything */ @@ -2574,8 +2480,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo) /* dummy write on Reg0 to be on "write index" mode next time */ vga_w(cinfo->regbase, VGA_ATT_IW, 0x00); - - DPRINTK("EXIT\n"); } /*** WHDR() - write into the Hidden DAC register ***/ @@ -2588,6 +2492,8 @@ static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val) { unsigned char dummy; + if (is_laguna(cinfo)) + return; if (cinfo->btype == BT_PICASSO) { /* Klaus' hint for correct access to HDR on some boards */ /* first write 0 to pixel mask (3c6) */ @@ -2655,7 +2561,8 @@ static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch vga_w(cinfo->regbase, VGA_PEL_IW, regnum); if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || - cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { + cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 || + cinfo->btype == BT_SD64 || is_laguna(cinfo)) { /* but DAC data register IS, at least for Picasso II */ if (cinfo->btype == BT_PICASSO) data += 0xfff; @@ -2702,9 +2609,8 @@ static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch /* FIXME: use interrupts instead */ static void cirrusfb_WaitBLT(u8 __iomem *regbase) { - /* now busy-wait until we're done */ while (vga_rgfx(regbase, CL_GR31) & 0x08) - /* do nothing */ ; + cpu_relax(); } /******************************************************************* @@ -2713,60 +2619,12 @@ static void cirrusfb_WaitBLT(u8 __iomem *regbase) perform accelerated "scrolling" ********************************************************************/ -static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, - u_short curx, u_short cury, - u_short destx, u_short desty, - u_short width, u_short height, - u_short line_length) -{ - u_short nwidth, nheight; - u_long nsrc, ndest; - u_char bltmode; - - DPRINTK("ENTER\n"); - - nwidth = width - 1; - nheight = height - 1; - - bltmode = 0x00; - /* if source adr < dest addr, do the Blt backwards */ - if (cury <= desty) { - if (cury == desty) { - /* if src and dest are on the same line, check x */ - if (curx < destx) - bltmode |= 0x01; - } else - bltmode |= 0x01; - } - if (!bltmode) { - /* standard case: forward blitting */ - nsrc = (cury * line_length) + curx; - ndest = (desty * line_length) + destx; - } else { - /* this means start addresses are at the end, - * counting backwards - */ - nsrc = cury * line_length + curx + - nheight * line_length + nwidth; - ndest = desty * line_length + destx + - nheight * line_length + nwidth; - } - - /* - run-down of registers to be programmed: - destination pitch - source pitch - BLT width/height - source start - destination start - BLT mode - BLT ROP - VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color" - start/stop - */ - - cirrusfb_WaitBLT(regbase); +static void cirrusfb_set_blitter(u8 __iomem *regbase, + u_short nwidth, u_short nheight, + u_long nsrc, u_long ndest, + u_short bltmode, u_short line_length) +{ /* pitch: set to line_length */ /* dest pitch low */ vga_wgfx(regbase, CL_GR24, line_length & 0xff); @@ -2813,91 +2671,91 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, /* and finally: GO! */ vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - - DPRINTK("EXIT\n"); } /******************************************************************* - cirrusfb_RectFill() + cirrusfb_BitBLT() - perform accelerated rectangle fill + perform accelerated "scrolling" ********************************************************************/ -static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, - u_short x, u_short y, u_short width, u_short height, - u_char color, u_short line_length) +static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length) { - u_short nwidth, nheight; - u_long ndest; - u_char op; - - DPRINTK("ENTER\n"); - - nwidth = width - 1; - nheight = height - 1; + u_short nwidth = width - 1; + u_short nheight = height - 1; + u_long nsrc, ndest; + u_char bltmode; - ndest = (y * line_length) + x; + bltmode = 0x00; + /* if source adr < dest addr, do the Blt backwards */ + if (cury <= desty) { + if (cury == desty) { + /* if src and dest are on the same line, check x */ + if (curx < destx) + bltmode |= 0x01; + } else + bltmode |= 0x01; + } + /* standard case: forward blitting */ + nsrc = (cury * line_length) + curx; + ndest = (desty * line_length) + destx; + if (bltmode) { + /* this means start addresses are at the end, + * counting backwards + */ + nsrc += nheight * line_length + nwidth; + ndest += nheight * line_length + nwidth; + } cirrusfb_WaitBLT(regbase); - /* pitch: set to line_length */ - vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ - vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */ - vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */ - vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */ + cirrusfb_set_blitter(regbase, nwidth, nheight, + nsrc, ndest, bltmode, line_length); +} - /* BLT width: actual number of pixels - 1 */ - vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ - vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */ +/******************************************************************* + cirrusfb_RectFill() - /* BLT height: actual number of lines -1 */ - vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */ - vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */ + perform accelerated rectangle fill +********************************************************************/ - /* BLT destination */ - /* BLT dest low */ - vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); - /* BLT dest mid */ - vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); - /* BLT dest hi */ - vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); +static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, + u_short x, u_short y, u_short width, u_short height, + u32 fg_color, u32 bg_color, u_short line_length, + u_char blitmode) +{ + u_long ndest = (y * line_length) + x; + u_char op; - /* BLT source: set to 0 (is a dummy here anyway) */ - vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */ - vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */ - vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */ + cirrusfb_WaitBLT(regbase); /* This is a ColorExpand Blt, using the */ /* same color for foreground and background */ - vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ - vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */ - - op = 0xc0; - if (bits_per_pixel == 16) { - vga_wgfx(regbase, CL_GR10, color); /* foreground color */ - vga_wgfx(regbase, CL_GR11, color); /* background color */ - op = 0x50; - op = 0xd0; - } else if (bits_per_pixel == 32) { - vga_wgfx(regbase, CL_GR10, color); /* foreground color */ - vga_wgfx(regbase, CL_GR11, color); /* background color */ - vga_wgfx(regbase, CL_GR12, color); /* foreground color */ - vga_wgfx(regbase, CL_GR13, color); /* background color */ - vga_wgfx(regbase, CL_GR14, 0); /* foreground color */ - vga_wgfx(regbase, CL_GR15, 0); /* background color */ - op = 0x50; - op = 0xf0; - } - /* BLT mode: color expand, Enable 8x8 copy (faster?) */ - vga_wgfx(regbase, CL_GR30, op); /* BLT mode */ - - /* BLT ROP: SrcCopy */ - vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ - - /* and finally: GO! */ - vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - - DPRINTK("EXIT\n"); + vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color); + vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color); + + op = 0x80; + if (bits_per_pixel >= 16) { + vga_wgfx(regbase, CL_GR10, bg_color >> 8); + vga_wgfx(regbase, CL_GR11, fg_color >> 8); + op = 0x90; + } + if (bits_per_pixel >= 24) { + vga_wgfx(regbase, CL_GR12, bg_color >> 16); + vga_wgfx(regbase, CL_GR13, fg_color >> 16); + op = 0xa0; + } + if (bits_per_pixel == 32) { + vga_wgfx(regbase, CL_GR14, bg_color >> 24); + vga_wgfx(regbase, CL_GR15, fg_color >> 24); + op = 0xb0; + } + cirrusfb_set_blitter(regbase, width - 1, height - 1, + 0, ndest, op | blitmode, line_length); } /************************************************************************** @@ -2917,8 +2775,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) *den = 0; *div = 0; - DPRINTK("ENTER\n"); - if (freq < 8000) freq = 8000; @@ -2960,12 +2816,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) } } } - - DPRINTK("Best possible values for given frequency:\n"); - DPRINTK(" freq: %ld kHz nom: %d den: %d div: %d\n", - freq, *nom, *den, *div); - - DPRINTK("EXIT\n"); } /* ------------------------------------------------------------------------- @@ -2978,32 +2828,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) #ifdef CIRRUSFB_DEBUG /** - * cirrusfb_dbg_print_byte - * @name: name associated with byte value to be displayed - * @val: byte value to be displayed - * - * DESCRIPTION: - * Display an indented string, along with a hexidecimal byte value, and - * its decoded bits. Bits 7 through 0 are listed in left-to-right - * order. - */ - -static -void cirrusfb_dbg_print_byte(const char *name, unsigned char val) -{ - DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", - name, val, - val & 0x80 ? '1' : '0', - val & 0x40 ? '1' : '0', - val & 0x20 ? '1' : '0', - val & 0x10 ? '1' : '0', - val & 0x08 ? '1' : '0', - val & 0x04 ? '1' : '0', - val & 0x02 ? '1' : '0', - val & 0x01 ? '1' : '0'); -} - -/** * cirrusfb_dbg_print_regs * @base: If using newmmio, the newmmio base address, otherwise %NULL * @reg_class: type of registers to read: %CRT, or %SEQ @@ -3014,9 +2838,9 @@ void cirrusfb_dbg_print_byte(const char *name, unsigned char val) * used at the given @base address to query the information. */ -static -void cirrusfb_dbg_print_regs(caddr_t regbase, - enum cirrusfb_dbg_reg_class reg_class, ...) +static void cirrusfb_dbg_print_regs(struct fb_info *info, + caddr_t regbase, + enum cirrusfb_dbg_reg_class reg_class, ...) { va_list list; unsigned char val = 0; @@ -3042,7 +2866,7 @@ void cirrusfb_dbg_print_regs(caddr_t regbase, break; } - cirrusfb_dbg_print_byte(name, val); + dev_dbg(info->device, "%8s = 0x%02X\n", name, val); name = va_arg(list, char *); } @@ -3051,18 +2875,6 @@ void cirrusfb_dbg_print_regs(caddr_t regbase, } /** - * cirrusfb_dump - * @cirrusfbinfo: - * - * DESCRIPTION: - */ - -static void cirrusfb_dump(void) -{ - cirrusfb_dbg_reg_dump(NULL); -} - -/** * cirrusfb_dbg_reg_dump * @base: If using newmmio, the newmmio base address, otherwise %NULL * @@ -3072,12 +2884,11 @@ static void cirrusfb_dump(void) * used at the given @base address to query the information. */ -static -void cirrusfb_dbg_reg_dump(caddr_t regbase) +static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase) { - DPRINTK("CIRRUSFB VGA CRTC register dump:\n"); + dev_dbg(info->device, "VGA CRTC register dump:\n"); - cirrusfb_dbg_print_regs(regbase, CRT, + cirrusfb_dbg_print_regs(info, regbase, CRT, "CR00", 0x00, "CR01", 0x01, "CR02", 0x02, @@ -3127,11 +2938,11 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase) "CR3F", 0x3F, NULL); - DPRINTK("\n"); + dev_dbg(info->device, "\n"); - DPRINTK("CIRRUSFB VGA SEQ register dump:\n"); + dev_dbg(info->device, "VGA SEQ register dump:\n"); - cirrusfb_dbg_print_regs(regbase, SEQ, + cirrusfb_dbg_print_regs(info, regbase, SEQ, "SR00", 0x00, "SR01", 0x01, "SR02", 0x02, @@ -3160,7 +2971,7 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase) "SR1F", 0x1F, NULL); - DPRINTK("\n"); + dev_dbg(info->device, "\n"); } #endif /* CIRRUSFB_DEBUG */ diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 1657b9608b04..2cd500a304f2 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2954,8 +2954,11 @@ static int fbcon_fb_unbind(int idx) static int fbcon_fb_unregistered(struct fb_info *info) { - int i, idx = info->node; + int i, idx; + if (!lock_fb_info(info)) + return -ENODEV; + idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) con2fb_map[i] = -1; @@ -2979,13 +2982,14 @@ static int fbcon_fb_unregistered(struct fb_info *info) } } - if (!num_registered_fb) - unregister_con_driver(&fb_con); - - if (primary_device == idx) primary_device = -1; + unlock_fb_info(info); + + if (!num_registered_fb) + unregister_con_driver(&fb_con); + return 0; } @@ -3021,9 +3025,13 @@ static inline void fbcon_select_primary(struct fb_info *info) static int fbcon_fb_registered(struct fb_info *info) { - int ret = 0, i, idx = info->node; + int ret = 0, i, idx; + if (!lock_fb_info(info)) + return -ENODEV; + idx = info->node; fbcon_select_primary(info); + unlock_fb_info(info); if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3124,7 +3132,7 @@ static void fbcon_get_requirement(struct fb_info *info, } } -static int fbcon_event_notify(struct notifier_block *self, +static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; @@ -3132,7 +3140,7 @@ static int fbcon_event_notify(struct notifier_block *self, struct fb_videomode *mode; struct fb_con2fbmap *con2fb; struct fb_blit_caps *caps; - int ret = 0; + int idx, ret = 0; /* * ignore all events except driver registration and deregistration @@ -3144,23 +3152,54 @@ static int fbcon_event_notify(struct notifier_block *self, switch(action) { case FB_EVENT_SUSPEND: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_suspended(info); + unlock_fb_info(info); break; case FB_EVENT_RESUME: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_resumed(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_modechanged(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE_ALL: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_set_all_vcs(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_DELETE: mode = event->data; + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } ret = fbcon_mode_deleted(info, mode); + unlock_fb_info(info); break; case FB_EVENT_FB_UNBIND: - ret = fbcon_fb_unbind(info->node); + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } + idx = info->node; + unlock_fb_info(info); + ret = fbcon_fb_unbind(idx); break; case FB_EVENT_FB_REGISTERED: ret = fbcon_fb_registered(info); @@ -3178,17 +3217,31 @@ static int fbcon_event_notify(struct notifier_block *self, con2fb->framebuffer = con2fb_map[con2fb->console - 1]; break; case FB_EVENT_BLANK: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_fb_blanked(info, *(int *)event->data); + unlock_fb_info(info); break; case FB_EVENT_NEW_MODELIST: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_new_modelist(info); + unlock_fb_info(info); break; case FB_EVENT_GET_REQ: caps = event->data; + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_get_requirement(info, caps); + unlock_fb_info(info); break; } - done: return ret; } diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c deleted file mode 100644 index 9704b73135f5..000000000000 --- a/drivers/video/cyblafb.c +++ /dev/null @@ -1,1683 +0,0 @@ -/* - * Frame buffer driver for Trident Cyberblade/i1 graphics core - * - * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de> - * - * CREDITS: - * tridentfb.c by Jani Monoses - * see files above for further credits - * - */ - -#define CYBLAFB_DEBUG 0 -#define CYBLAFB_KD_GRAPHICS_QUIRK 1 - -#define CYBLAFB_PIXMAPSIZE 8192 - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <asm/types.h> -#include <video/cyblafb.h> - -#define VERSION "0.62" - -struct cyblafb_par { - u32 pseudo_pal[16]; - struct fb_ops ops; -}; - -static struct fb_fix_screeninfo cyblafb_fix __devinitdata = { - .id = "CyBla", - .type = FB_TYPE_PACKED_PIXELS, - .xpanstep = 1, - .ypanstep = 1, - .ywrapstep = 1, - .visual = FB_VISUAL_PSEUDOCOLOR, - .accel = FB_ACCEL_NONE, -}; - -static char *mode __devinitdata = NULL; -static int bpp __devinitdata = 8; -static int ref __devinitdata = 75; -static int fp __devinitdata; -static int crt __devinitdata; -static int memsize __devinitdata; - -static int basestride; -static int vesafb; -static int nativex; -static int center; -static int stretch; -static int pciwb = 1; -static int pcirb = 1; -static int pciwr = 1; -static int pcirr = 1; -static int disabled; -static int verbosity; -static int displaytype; - -static void __iomem *io_virt; // iospace virtual memory address - -module_param(mode, charp, 0); -module_param(bpp, int, 0); -module_param(ref, int, 0); -module_param(fp, int, 0); -module_param(crt, int, 0); -module_param(nativex, int, 0); -module_param(center, int, 0); -module_param(stretch, int, 0); -module_param(pciwb, int, 0); -module_param(pcirb, int, 0); -module_param(pciwr, int, 0); -module_param(pcirr, int, 0); -module_param(memsize, int, 0); -module_param(verbosity, int, 0); - -//========================================= -// -// Well, we have to fix the upper layers. -// Until this has been done, we work around -// the bugs. -// -//========================================= - -#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG) - if (disabled) { \ - printk("********\n");\ - dump_stack();\ - return val;\ - } - -#elif CYBLAFB_KD_GRAPHICS_QUIRK -#define KD_GRAPHICS_RETURN(val)\ - if (disabled) {\ - return val;\ - } -#else -#define KD_GRAPHICS_RETURN(val) -#endif - -//========================================= -// -// Port access macros for memory mapped io -// -//========================================= - -#define out8(r, v) writeb(v, io_virt + r) -#define out32(r, v) writel(v, io_virt + r) -#define in8(r) readb(io_virt + r) -#define in32(r) readl(io_virt + r) - -//====================================== -// -// Hardware access inline functions -// -//====================================== - -static inline u8 read3X4(u32 reg) -{ - out8(0x3D4, reg); - return in8(0x3D5); -} - -static inline u8 read3C4(u32 reg) -{ - out8(0x3C4, reg); - return in8(0x3C5); -} - -static inline u8 read3CE(u32 reg) -{ - out8(0x3CE, reg); - return in8(0x3CF); -} - -static inline void write3X4(u32 reg, u8 val) -{ - out8(0x3D4, reg); - out8(0x3D5, val); -} - -static inline void write3C4(u32 reg, u8 val) -{ - out8(0x3C4, reg); - out8(0x3C5, val); -} - -static inline void write3CE(u32 reg, u8 val) -{ - out8(0x3CE, reg); - out8(0x3CF, val); -} - -static inline void write3C0(u32 reg, u8 val) -{ - in8(0x3DA); // read to reset index - out8(0x3C0, reg); - out8(0x3C0, val); -} - -//================================================= -// -// Enable memory mapped io and unprotect registers -// -//================================================= - -static void enable_mmio(void) -{ - u8 tmp; - - outb(0x0B, 0x3C4); - inb(0x3C5); // Set NEW mode - outb(SR0E, 0x3C4); // write enable a lot of extended ports - outb(0x80, 0x3C5); - - outb(SR11, 0x3C4); // write enable those extended ports that - outb(0x87, 0x3C5); // are not affected by SR0E_New - - outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2 - tmp = inb(0x3d5) & 0xBF; - outb(CR1E, 0x3d4); - outb(tmp, 0x3d5); - - outb(CR39, 0x3D4); - outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio -} - -//================================================= -// -// Set pixel clock VCLK1 -// - multipliers set elswhere -// - freq in units of 0.01 MHz -// -// Hardware bug: SR18 >= 250 is broken for the -// cyberblade/i1 -// -//================================================= - -static void set_vclk(struct cyblafb_par *par, int freq) -{ - u32 m, n, k; - int f, fi, d, di; - u8 lo = 0, hi = 0; - - d = 2000; - k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3; - for (m = 0; m < 64; m++) - for (n = 0; n < 250; n++) { - fi = (int)(((5864727 * (n + 8)) / - ((m + 2) * (1 << k))) >> 12); - if ((di = abs(fi - freq)) < d) { - d = di; - f = fi; - lo = (u8) n; - hi = (u8) ((k << 6) | m); - } - } - write3C4(SR19, hi); - write3C4(SR18, lo); - if (verbosity > 0) - output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n", - freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo); -} - -//================================================ -// -// Cyberblade specific Graphics Engine (GE) setup -// -//================================================ - -static void cyblafb_setup_GE(int pitch, int bpp) -{ - KD_GRAPHICS_RETURN(); - - switch (bpp) { - case 8: - basestride = ((pitch >> 3) << 20) | (0 << 29); - break; - case 15: - basestride = ((pitch >> 3) << 20) | (5 << 29); - break; - case 16: - basestride = ((pitch >> 3) << 20) | (1 << 29); - break; - case 24: - case 32: - basestride = ((pitch >> 3) << 20) | (2 << 29); - break; - } - - write3X4(CR36, 0x90); // reset GE - write3X4(CR36, 0x80); // enable GE - out32(GE24, 1 << 7); // reset all GE pointers by toggling - out32(GE24, 0); // d7 of GE24 - write3X4(CR2D, 0x00); // GE Timinigs, no delays - out32(GE6C, 0); // Pattern and Style, p 129, ok -} - -//===================================================================== -// -// Cyberblade specific syncing -// -// A timeout might be caused by disabled mmio. -// Cause: -// - bit CR39 & 1 == 0 upon return, X trident driver bug -// - kdm bug (KD_GRAPHICS not set on first switch) -// - kernel design flaw (it believes in the correctness -// of kdm/X -// First we try to sync ignoring that problem, as most of the -// time that will succeed immediately and the enable_mmio() -// would only degrade performance. -// -//===================================================================== - -static int cyblafb_sync(struct fb_info *info) -{ - u32 status, i = 100000; - - KD_GRAPHICS_RETURN(0); - - while (((status = in32(GE20)) & 0xFe800000) && i != 0) - i--; - - if (i == 0) { - enable_mmio(); - i = 1000000; - while (((status = in32(GE20)) & 0xFA800000) && i != 0) - i--; - if (i == 0) { - output("GE Timeout, status: %x\n", status); - if (status & 0x80000000) - output("Bresenham Engine : Busy\n"); - if (status & 0x40000000) - output("Setup Engine : Busy\n"); - if (status & 0x20000000) - output("SP / DPE : Busy\n"); - if (status & 0x10000000) - output("Memory Interface : Busy\n"); - if (status & 0x08000000) - output("Com Lst Proc : Busy\n"); - if (status & 0x04000000) - output("Block Write : Busy\n"); - if (status & 0x02000000) - output("Command Buffer : Full\n"); - if (status & 0x01000000) - output("RESERVED : Busy\n"); - if (status & 0x00800000) - output("PCI Write Buffer : Busy\n"); - cyblafb_setup_GE(info->var.xres, - info->var.bits_per_pixel); - } - } - - return 0; -} - -//============================== -// -// Cyberblade specific fillrect -// -//============================== - -static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr) -{ - u32 bpp = info->var.bits_per_pixel, col, desty, height; - - KD_GRAPHICS_RETURN(); - - switch (bpp) { - default: - case 8: - col = fr->color; - col |= col << 8; - col |= col << 16; - break; - case 16: - col = ((u32 *) (info->pseudo_palette))[fr->color]; - col |= col << 16; - break; - case 32: - col = ((u32 *) (info->pseudo_palette))[fr->color]; - break; - } - - desty = fr->dy; - height = fr->height; - while (height) { - out32(GEB8, basestride | ((desty * info->var.xres_virtual * - bpp) >> 6)); - out32(GE60, col); - out32(GE48, fr->rop ? 0x66 : ROP_S); - out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); - out32(GE08, point(fr->dx, 0)); - out32(GE0C, point(fr->dx + fr->width - 1, - height > 4096 ? 4095 : height - 1)); - if (likely(height <= 4096)) - return; - desty += 4096; - height -= 4096; - } -} - -//================================================ -// -// Cyberblade specific copyarea -// -// This function silently assumes that it never -// will be called with width or height exceeding -// 4096. -// -//================================================ - -static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) -{ - u32 s1, s2, d1, d2, direction; - - KD_GRAPHICS_RETURN(); - - s1 = point(ca->sx, 0); - s2 = point(ca->sx + ca->width - 1, ca->height - 1); - d1 = point(ca->dx, 0); - d2 = point(ca->dx + ca->width - 1, ca->height - 1); - - if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx))) - direction = 0; - else - direction = 2; - - out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual * - info->var.bits_per_pixel) >> 6)); - out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual * - info->var.bits_per_pixel) >> 6)); - out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction); - out32(GE00, direction ? s2 : s1); - out32(GE04, direction ? s1 : s2); - out32(GE08, direction ? d2 : d1); - out32(GE0C, direction ? d1 : d2); -} - -//======================================================================= -// -// Cyberblade specific imageblit -// -// Accelerated for the most usual case, blitting 1 - bit deep -// character images. Everything else is passed to the generic imageblit -// unless it is so insane that it is better to printk an alert. -// -// Hardware bug: _Never_ blit across pixel column 2048, that will lock -// the system. We split those blit requests into three blitting -// operations. -// -//======================================================================= - -static void cyblafb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - u32 fgcol, bgcol; - u32 *pd = (u32 *) image->data; - u32 bpp = info->var.bits_per_pixel; - - KD_GRAPHICS_RETURN(); - - // Used only for drawing the penguine (image->depth > 1) - if (image->depth != 1) { - cfb_imageblit(info, image); - return; - } - // That should never happen, but it would be fatal - if (image->width == 0 || image->height == 0) { - output("imageblit: width/height 0 detected\n"); - return; - } - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color]; - bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color]; - } else { - fgcol = image->fg_color; - bgcol = image->bg_color; - } - - switch (bpp) { - case 8: - fgcol |= fgcol << 8; - bgcol |= bgcol << 8; - case 16: - fgcol |= fgcol << 16; - bgcol |= bgcol << 16; - default: - break; - } - - out32(GEB8, basestride | ((image->dy * info->var.xres_virtual * - bpp) >> 6)); - out32(GE60, fgcol); - out32(GE64, bgcol); - - if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) { - u32 dds = ((image->width + 31) >> 5) * image->height; - out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); - out32(GE08, point(image->dx, 0)); - out32(GE0C, point(image->dx + image->width - 1, - image->height - 1)); - while (dds--) - out32(GE9C, *pd++); - } else { - int i, j; - u32 ddstotal = (image->width + 31) >> 5; - u32 ddsleft = (2048 - image->dx + 31) >> 5; - u32 skipleft = ddstotal - ddsleft; - - out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); - out32(GE08, point(image->dx, 0)); - out32(GE0C, point(2048 - 1, image->height - 1)); - for (i = 0; i < image->height; i++) { - for (j = 0; j < ddsleft; j++) - out32(GE9C, *pd++); - pd += skipleft; - } - - if (image->dx % 32) { - out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); - out32(GE08, point(2048, 0)); - if (image->width > ddsleft << 5) - out32(GE0C, point(image->dx + (ddsleft << 5) - - 1, image->height - 1)); - else - out32(GE0C, point(image->dx + image->width - 1, - image->height - 1)); - pd = ((u32 *) image->data) + ddstotal - skipleft - 1; - for (i = 0; i < image->height; i++) { - out32(GE9C, swab32(swab32(*pd) << ((32 - - (image->dx & 31)) & 31))); - pd += ddstotal; - } - } - - if (skipleft) { - out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); - out32(GE08, point(image->dx + (ddsleft << 5), 0)); - out32(GE0C, point(image->dx + image->width - 1, - image->height - 1)); - pd = (u32 *) image->data; - for (i = 0; i < image->height; i++) { - pd += ddsleft; - for (j = 0; j < skipleft; j++) - out32(GE9C, *pd++); - } - } - } -} - -//========================================================== -// -// Check if video mode is acceptable. We change var->??? if -// video mode is slightly off or return error otherwise. -// info->??? must not be changed! -// -//========================================================== - -static int cyblafb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - int bpp = var->bits_per_pixel; - - // - // we try to support 8, 16, 24 and 32 bpp modes, - // default to 8 - // - // there is a 24 bpp mode, but for now we change requests to 32 bpp - // (This is what tridentfb does ... will be changed in the future) - // - // - if (bpp % 8 != 0 || bpp < 8 || bpp > 32) - bpp = 8; - if (bpp == 24) - bpp = var->bits_per_pixel = 32; - - // - // interlaced modes are broken, fail if one is requested - // - if (var->vmode & FB_VMODE_INTERLACED) - return -EINVAL; - - // - // fail if requested resolution is higher than physical - // flatpanel resolution - // - if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex) - return -EINVAL; - - // - // we do not allow vclk to exceed 230 MHz. If the requested - // vclk is too high, we default to 200 MHz - // - if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000) - var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000; - - // - // enforce (h|v)sync_len limits - // - var->hsync_len &= ~7; - if(var->hsync_len > 248) - var->hsync_len = 248; - - var->vsync_len &= 15; - - // - // Enforce horizontal and vertical hardware limits. - // 1600x1200 is mentioned as a maximum, but higher resolutions could - // work with slow refresh, small margins and short sync. - // - var->xres &= ~7; - - if (((var->xres + var->left_margin + var->right_margin + - var->hsync_len) > (bpp == 32 ? 2040 : 4088)) || - ((var->yres + var->upper_margin + var->lower_margin + - var->vsync_len) > 2047)) - return -EINVAL; - - if ((var->xres > 1600) || (var->yres > 1200)) - output("Mode %dx%d exceeds documented limits.\n", - var->xres, var->yres); - // - // try to be smart about (x|y)res_virtual problems. - // - if (var->xres > var->xres_virtual) - var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual) - var->yres_virtual = var->yres; - - if (bpp == 8 || bpp == 16) { - if (var->xres_virtual > 4088) - var->xres_virtual = 4088; - } else { - if (var->xres_virtual > 2040) - var->xres_virtual = 2040; - } - var->xres_virtual &= ~7; - while (var->xres_virtual * var->yres_virtual * bpp / 8 > - info->fix.smem_len) { - if (var->yres_virtual > var->yres) - var->yres_virtual--; - else if (var->xres_virtual > var->xres) - var->xres_virtual -= 8; - else - return -EINVAL; - } - - switch (bpp) { - case 8: - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - break; - case 16: - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - break; - default: - return -EINVAL; - } - - return 0; -} - -//===================================================================== -// -// Pan the display -// -// The datasheets defines crt start address to be 20 bits wide and -// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is -// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use -// it, so it is also safe to be used here. BTW: datasheet CR0E on page -// 90 really is CR1E, the real CRE is documented on page 72. -// -// BUT: -// -// As of internal version 0.60 we do not use vga panning any longer. -// Vga panning did not allow us the use of all available video memory -// and thus prevented ywrap scrolling. We do use the "right view" -// register now. -// -// -//===================================================================== - -static int cyblafb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - KD_GRAPHICS_RETURN(0); - - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset * - var->xres_virtual)) * var->bits_per_pixel / 32)); - return 0; -} - -//============================================ -// -// This will really help in case of a bug ... -// dump most gaphics core registers. -// -//============================================ - -static void regdump(struct cyblafb_par *par) -{ - int i; - - if (verbosity < 2) - return; - - printk("\n"); - for (i = 0; i <= 0xff; i++) { - outb(i, 0x3d4); - printk("CR%02x=%02x ", i, inb(0x3d5)); - if (i % 16 == 15) - printk("\n"); - } - - outb(0x30, 0x3ce); - outb(inb(0x3cf) | 0x40, 0x3cf); - for (i = 0; i <= 0x1f; i++) { - if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11 - || i == 0x16) { - outb(i, 0x3d4); - printk("CR%02x=%02x ", i, inb(0x3d5)); - } else - printk("------- "); - if (i % 16 == 15) - printk("\n"); - } - outb(0x30, 0x3ce); - outb(inb(0x3cf) & 0xbf, 0x3cf); - - printk("\n"); - for (i = 0; i <= 0x7f; i++) { - outb(i, 0x3ce); - printk("GR%02x=%02x ", i, inb(0x3cf)); - if (i % 16 == 15) - printk("\n"); - } - - printk("\n"); - for (i = 0; i <= 0xff; i++) { - outb(i, 0x3c4); - printk("SR%02x=%02x ", i, inb(0x3c5)); - if (i % 16 == 15) - printk("\n"); - } - - printk("\n"); - for (i = 0; i <= 0x1F; i++) { - inb(0x3da); // next access is index! - outb(i, 0x3c0); - printk("AR%02x=%02x ", i, inb(0x3c1)); - if (i % 16 == 15) - printk("\n"); - } - printk("\n"); - - inb(0x3DA); // reset internal flag to 3c0 index - outb(0x20, 0x3C0); // enable attr - - return; -} - -//======================================================================= -// -// Save State -// -// This function is called while a switch to KD_TEXT is in progress, -// before any of the other functions are called. -// -//======================================================================= - -static void cyblafb_save_state(struct fb_info *info) -{ - struct cyblafb_par *par = info->par; - if (verbosity > 0) - output("Switching to KD_TEXT\n"); - disabled = 0; - regdump(par); - enable_mmio(); - return; -} - -//======================================================================= -// -// Restore State -// -// This function is called while a switch to KD_GRAPHICS is in progress, -// We have to turn on vga style panning registers again because the -// trident driver of X does not know about GE10. -// -//======================================================================= - -static void cyblafb_restore_state(struct fb_info *info) -{ - if (verbosity > 0) - output("Switching to KD_GRAPHICS\n"); - out32(GE10, 0); - disabled = 1; - return; -} - -//====================================== -// -// Set hardware to requested video mode -// -//====================================== - -static int cyblafb_set_par(struct fb_info *info) -{ - struct cyblafb_par *par = info->par; - u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, - hblankend, preendfetch, vtotal, vdispend, vsyncstart, - vsyncend, vblankstart, vblankend; - struct fb_var_screeninfo *var = &info->var; - int bpp = var->bits_per_pixel; - int i; - - KD_GRAPHICS_RETURN(0); - - if (verbosity > 0) - output("Switching to new mode: " - "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n", - var->xres, var->yres, var->xres_virtual, - var->yres_virtual, var->bits_per_pixel, var->pixclock, - var->left_margin, var->right_margin, var->upper_margin, - var->lower_margin, var->hsync_len, var->vsync_len); - - htotal = (var->xres + var->left_margin + var->right_margin + - var->hsync_len) / 8 - 5; - hdispend = var->xres / 8 - 1; - hsyncstart = (var->xres + var->right_margin) / 8; - hsyncend = var->hsync_len / 8; - hblankstart = hdispend + 1; - hblankend = htotal + 3; // should be htotal + 5, bios does it this way - preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3); - - vtotal = var->yres + var->upper_margin + var->lower_margin + - var->vsync_len - 2; - vdispend = var->yres - 1; - vsyncstart = var->yres + var->lower_margin; - vblankstart = var->yres; - vblankend = vtotal; // should be vtotal + 2, but bios does it this way - vsyncend = var->vsync_len; - - enable_mmio(); // necessary! ... check X ... - - write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 - - write3CE(GR30, 8); - - if ((displaytype == DISPLAY_FP) && var->xres < nativex) { - - // stretch or center ? - - out8(0x3C2, 0xEB); - - write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on - - if (center) { - write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80); - write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80); - } else if (stretch) { - write3CE(GR5D, 0); - write3CE(GR52, (read3CE(GR52) & 0x7C) | 1); - write3CE(GR53, (read3CE(GR53) & 0x7C) | 1); - } - - } else { - out8(0x3C2, 0x2B); - write3CE(GR30, 8); - } - - // - // Setup CRxx regs - // - - write3X4(CR00, htotal & 0xFF); - write3X4(CR01, hdispend & 0xFF); - write3X4(CR02, hblankstart & 0xFF); - write3X4(CR03, hblankend & 0x1F); - write3X4(CR04, hsyncstart & 0xFF); - write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); - write3X4(CR06, vtotal & 0xFF); - write3X4(CR07, (vtotal & 0x100) >> 8 | - (vdispend & 0x100) >> 7 | - (vsyncstart & 0x100) >> 6 | - (vblankstart & 0x100) >> 5 | - 0x10 | - (vtotal & 0x200) >> 4 | - (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2); - write3X4(CR08, 0); - write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!! - ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0)); - write3X4(CR0A, 0); // Init to some reasonable default - write3X4(CR0B, 0); // Init to some reasonable default - write3X4(CR0C, 0); // Offset 0 - write3X4(CR0D, 0); // Offset 0 - write3X4(CR0E, 0); // Init to some reasonable default - write3X4(CR0F, 0); // Init to some reasonable default - write3X4(CR10, vsyncstart & 0xFF); - write3X4(CR11, (vsyncend & 0x0F)); - write3X4(CR12, vdispend & 0xFF); - write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF); - write3X4(CR14, 0x40); // double word mode - write3X4(CR15, vblankstart & 0xFF); - write3X4(CR16, vblankend & 0xFF); - write3X4(CR17, 0xE3); - write3X4(CR18, 0xFF); - // CR19: needed for interlaced modes ... ignore it for now - write3X4(CR1A, 0x07); // Arbitration Control Counter 1 - write3X4(CR1B, 0x07); // Arbitration Control Counter 2 - write3X4(CR1C, 0x07); // Arbitration Control Counter 3 - write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -) - write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80); - // CR1F: do not set, contains BIOS info about memsize - write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode - write3X4(CR21, 0x20); // enable linear memory access - // CR22: RO cpu latch readback - // CR23: ??? - // CR24: RO AR flag state - // CR25: RAMDAC rw timing, pclk buffer tristate control ???? - // CR26: ??? - write3X4(CR27, (vdispend & 0x400) >> 6 | - (vsyncstart & 0x400) >> 5 | - (vblankstart & 0x400) >> 4 | - (vtotal & 0x400) >> 3 | - 0x8); - // CR28: ??? - write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual * - bpp) / (4 * 16)) & 0x300) >> 4)); - write3X4(CR2A, read3X4(CR2A) | 0x40); - write3X4(CR2B, (htotal & 0x100) >> 8 | - (hdispend & 0x100) >> 7 | - // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ??? - (hsyncstart & 0x100) >> 5 | - (hblankstart & 0x100) >> 4); - // CR2C: ??? - // CR2D: initialized in cyblafb_setup_GE() - write3X4(CR2F, 0x92); // conservative, better signal quality - // CR30: reserved - // CR31: reserved - // CR32: reserved - // CR33: reserved - // CR34: disabled in CR36 - // CR35: disabled in CR36 - // CR36: initialized in cyblafb_setup_GE - // CR37: i2c, ignore for now - write3X4(CR38, (bpp == 8) ? 0x00 : // - (bpp == 16) ? 0x05 : // highcolor - (bpp == 24) ? 0x29 : // packed 24bit truecolor - (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus - write3X4(CR39, 0x01 | // MMIO enable - (pcirb ? 0x02 : 0) | // pci read burst enable - (pciwb ? 0x04 : 0)); // pci write burst enable - write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase - (pcirr ? 0x40 : 0) | // pci read retry enable - (pciwr ? 0x80 : 0)); // pci write retry enable - write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2 - : 0); - write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0); - write3X4(CR58, 0x82); // Bios does this .... don't know more - // - // Setup SRxx regs - // - write3C4(SR00, 3); - write3C4(SR01, 1); //set char clock 8 dots wide - write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode - write3C4(SR03, 0); //no character map select - write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4 - - out8(0x3C4, 0x0b); - in8(0x3C5); // Set NEW mode - write3C4(SR0D, 0x00); // test ... check - - set_vclk(par, (bpp == 32 ? 200000000 : 100000000) - / info->var.pixclock); //SR18, SR19 - - // - // Setup GRxx regs - // - write3CE(GR00, 0x00); // test ... check - write3CE(GR01, 0x00); // test ... check - write3CE(GR02, 0x00); // test ... check - write3CE(GR03, 0x00); // test ... check - write3CE(GR04, 0x00); // test ... check - write3CE(GR05, 0x40); // no CGA compat, allow 256 col - write3CE(GR06, 0x05); // graphics mode - write3CE(GR07, 0x0F); // planes? - write3CE(GR08, 0xFF); // test ... check - write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4 - write3CE(GR20, 0xC0); // test ... check - write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew, - - // - // Setup ARxx regs - // - for (i = 0; i < 0x10; i++) // set AR00 .. AR0f - write3C0(i, i); - write3C0(AR10, 0x41); // graphics mode and support 256 color modes - write3C0(AR12, 0x0F); // planes - write3C0(AR13, 0); // horizontal pel panning - in8(0x3DA); // reset internal flag to 3c0 index - out8(0x3C0, 0x20); // enable attr - - // - // Setup hidden RAMDAC command register - // - in8(0x3C8); // these reads are - in8(0x3C6); // necessary to - in8(0x3C6); // unmask the RAMDAC - in8(0x3C6); // command reg, otherwise - in8(0x3C6); // we would write the pixelmask reg! - out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors - (bpp == 15) ? 0x10 : // - (bpp == 16) ? 0x30 : // hicolor - (bpp == 24) ? 0xD0 : // truecolor - (bpp == 32) ? 0xD0 : 0); // truecolor - in8(0x3C8); - - // - // GR31 is not mentioned in the datasheet - // - if (displaytype == DISPLAY_FP) - write3CE(GR31, (read3CE(GR31) & 0x8F) | - ((info->var.yres > 1024) ? 0x50 : - (info->var.yres > 768) ? 0x30 : - (info->var.yres > 600) ? 0x20 : - (info->var.yres > 480) ? 0x10 : 0)); - - info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_TRUECOLOR; - info->fix.line_length = info->var.xres_virtual * (bpp >> 3); - info->cmap.len = (bpp == 8) ? 256 : 16; - - // - // init acceleration engine - // - cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel); - - // - // Set/clear flags to allow proper scroll mode selection. - // - if (var->xres == var->xres_virtual) - info->flags &= ~FBINFO_HWACCEL_XPAN; - else - info->flags |= FBINFO_HWACCEL_XPAN; - - if (var->yres == var->yres_virtual) - info->flags &= ~FBINFO_HWACCEL_YPAN; - else - info->flags |= FBINFO_HWACCEL_YPAN; - - if (info->fix.smem_len != - var->xres_virtual * var->yres_virtual * bpp / 8) - info->flags &= ~FBINFO_HWACCEL_YWRAP; - else - info->flags |= FBINFO_HWACCEL_YWRAP; - - regdump(par); - - return 0; -} - -//======================== -// -// Set one color register -// -//======================== - -static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - int bpp = info->var.bits_per_pixel; - - KD_GRAPHICS_RETURN(0); - - if (regno >= info->cmap.len) - return 1; - - if (bpp == 8) { - out8(0x3C6, 0xFF); - out8(0x3C8, regno); - out8(0x3C9, red >> 10); - out8(0x3C9, green >> 10); - out8(0x3C9, blue >> 10); - - } else if (regno < 16) { - if (bpp == 16) // RGB 565 - ((u32 *) info->pseudo_palette)[regno] = - (red & 0xF800) | - ((green & 0xFC00) >> 5) | - ((blue & 0xF800) >> 11); - else if (bpp == 32) // ARGB 8888 - ((u32 *) info->pseudo_palette)[regno] = - ((transp & 0xFF00) << 16) | - ((red & 0xFF00) << 8) | - ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); - } - - return 0; -} - -//========================================================== -// -// Try blanking the screen. For flat panels it does nothing -// -//========================================================== - -static int cyblafb_blank(int blank_mode, struct fb_info *info) -{ - unsigned char PMCont, DPMSCont; - - KD_GRAPHICS_RETURN(0); - - if (displaytype == DISPLAY_FP) - return 0; - - out8(0x83C8, 0x04); // DPMS Control - PMCont = in8(0x83C6) & 0xFC; - - DPMSCont = read3CE(GR23) & 0xFC; - - switch (blank_mode) { - case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On - case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On - PMCont |= 0x03; - DPMSCont |= 0x00; - break; - case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On - PMCont |= 0x02; - DPMSCont |= 0x01; - break; - case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off - PMCont |= 0x02; - DPMSCont |= 0x02; - break; - case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off - PMCont |= 0x00; - DPMSCont |= 0x03; - break; - } - - write3CE(GR23, DPMSCont); - out8(0x83C8, 4); - out8(0x83C6, PMCont); - // - // let fbcon do a softblank for us - // - return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; -} - -static struct fb_ops cyblafb_ops __devinitdata = { - .owner = THIS_MODULE, - .fb_setcolreg = cyblafb_setcolreg, - .fb_pan_display = cyblafb_pan_display, - .fb_blank = cyblafb_blank, - .fb_check_var = cyblafb_check_var, - .fb_set_par = cyblafb_set_par, - .fb_fillrect = cyblafb_fillrect, - .fb_copyarea = cyblafb_copyarea, - .fb_imageblit = cyblafb_imageblit, - .fb_sync = cyblafb_sync, - .fb_restore_state = cyblafb_restore_state, - .fb_save_state = cyblafb_save_state, -}; - -//========================================================================== -// -// getstartupmode() decides about the inital video mode -// -// There is no reason to use modedb, a lot of video modes there would -// need altered timings to display correctly. So I decided that it is much -// better to provide a limited optimized set of modes plus the option of -// using the mode in effect at startup time (might be selected using the -// vga=??? parameter). After that the user might use fbset to select any -// mode he likes, check_var will not try to alter geometry parameters as -// it would be necessary otherwise. -// -//========================================================================== - -static int __devinit getstartupmode(struct fb_info *info) -{ - u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend, - vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend, - cr00, cr01, cr02, cr03, cr04, cr05, cr2b, - cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27, - cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i; - - struct modus { - int xres; int vxres; int yres; int vyres; - int bpp; int pxclk; - int left_margin; int right_margin; - int upper_margin; int lower_margin; - int hsync_len; int vsync_len; - } modedb[5] = { - { - 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, { - 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, { - 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, { - 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, { - 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3} - }; - - outb(0x00, 0x3d4); cr00 = inb(0x3d5); - outb(0x01, 0x3d4); cr01 = inb(0x3d5); - outb(0x02, 0x3d4); cr02 = inb(0x3d5); - outb(0x03, 0x3d4); cr03 = inb(0x3d5); - outb(0x04, 0x3d4); cr04 = inb(0x3d5); - outb(0x05, 0x3d4); cr05 = inb(0x3d5); - outb(0x06, 0x3d4); cr06 = inb(0x3d5); - outb(0x07, 0x3d4); cr07 = inb(0x3d5); - outb(0x09, 0x3d4); cr09 = inb(0x3d5); - outb(0x10, 0x3d4); cr10 = inb(0x3d5); - outb(0x11, 0x3d4); cr11 = inb(0x3d5); - outb(0x12, 0x3d4); cr12 = inb(0x3d5); - outb(0x15, 0x3d4); cr15 = inb(0x3d5); - outb(0x16, 0x3d4); cr16 = inb(0x3d5); - outb(0x27, 0x3d4); cr27 = inb(0x3d5); - outb(0x2b, 0x3d4); cr2b = inb(0x3d5); - outb(0x38, 0x3d4); cr38 = inb(0x3d5); - - outb(0x0b, 0x3c4); - inb(0x3c5); - - outb(0x0d, 0x3c4); sr0d = inb(0x3c5); - outb(0x18, 0x3c4); sr18 = inb(0x3c5); - outb(0x19, 0x3c4); sr19 = inb(0x3c5); - outb(0x0f, 0x3ce); gr0f = inb(0x3cf); - - htotal = cr00 | (cr2b & 0x01) << 8; - hdispend = cr01 | (cr2b & 0x02) << 7; - hblankstart = cr02 | (cr2b & 0x10) << 4; - hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2; - hsyncstart = cr04 | (cr2b & 0x08) << 5; - hsyncend = cr05 & 0x1f; - - modedb[0].xres = hblankstart * 8; - modedb[0].hsync_len = hsyncend * 8; - modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres; - modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres - - modedb[0].right_margin - modedb[0].hsync_len; - - vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4 - | (cr27 & 0x80) << 3; - vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3 - | (cr27 & 0x10) << 6; - vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2 - | (cr27 & 0x20) << 5; - vsyncend = cr11 & 0x0f; - vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4 - | (cr27 & 0x40) << 4; - vblankend = cr16; - - modedb[0].yres = vdispend + 1; - modedb[0].vsync_len = vsyncend; - modedb[0].lower_margin = vsyncstart - modedb[0].yres; - modedb[0].upper_margin = vtotal - modedb[0].yres - - modedb[0].lower_margin - modedb[0].vsync_len + 2; - - tmp = cr38 & 0x3c; - modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 : - tmp == 8 ? 32 : 8; - - fi = ((5864727 * (sr18 + 8)) / - (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12; - pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1; - tmp = sr0d & 0x06; - vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 ! - modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi; - - if (verbosity > 0) - output("detected startup mode: " - "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n", - modedb[0].xres, modedb[0].yres, modedb[0].xres, - modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin, - modedb[0].right_margin, modedb[0].upper_margin, - modedb[0].lower_margin, modedb[0].hsync_len, - modedb[0].vsync_len); - - // - // We use this goto target in case of a failed check_var. No, I really - // do not want to do it in another way! - // - - tryagain: - - i = (mode == NULL) ? 0 : - !strncmp(mode, "640x480", 7) ? 1 : - !strncmp(mode, "800x600", 7) ? 2 : - !strncmp(mode, "1024x768", 8) ? 3 : - !strncmp(mode, "1280x1024", 9) ? 4 : 0; - - ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref; - - if (i == 0) { - info->var.pixclock = modedb[i].pxclk; - info->var.bits_per_pixel = modedb[i].bpp; - } else { - info->var.pixclock = (100000000 / - ((modedb[i].left_margin + - modedb[i].xres + - modedb[i].right_margin + - modedb[i].hsync_len) * - (modedb[i].upper_margin + - modedb[i].yres + - modedb[i].lower_margin + - modedb[i].vsync_len) * ref / 10000)); - info->var.bits_per_pixel = bpp; - } - - info->var.left_margin = modedb[i].left_margin; - info->var.right_margin = modedb[i].right_margin; - info->var.xres = modedb[i].xres; - if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32)) - info->var.xres_virtual = modedb[i].vxres; - else - info->var.xres_virtual = modedb[i].xres; - info->var.xoffset = 0; - info->var.hsync_len = modedb[i].hsync_len; - info->var.upper_margin = modedb[i].upper_margin; - info->var.yres = modedb[i].yres; - info->var.yres_virtual = modedb[i].vyres; - info->var.yoffset = 0; - info->var.lower_margin = modedb[i].lower_margin; - info->var.vsync_len = modedb[i].vsync_len; - info->var.sync = 0; - info->var.vmode = FB_VMODE_NONINTERLACED; - - if (cyblafb_check_var(&info->var, info)) { - // 640x480 - 8@75 should really never fail. One case would - // be fp == 1 and nativex < 640 ... give up then - if (i == 1 && bpp == 8 && ref == 75) { - output("Can't find a valid mode :-(\n"); - return -EINVAL; - } - // Our detected mode is unlikely to fail. If it does, - // try 640x480 - 8@75 ... - if (i == 0) { - mode = "640x480"; - bpp = 8; - ref = 75; - output("Detected mode failed check_var! " - "Trying 640x480 - 8@75\n"); - goto tryagain; - } - // A specified video mode failed for some reason. - // Try the startup mode first - output("Specified mode '%s' failed check! " - "Falling back to startup mode.\n", mode); - mode = NULL; - goto tryagain; - } - - return 0; -} - -//======================================================== -// -// Detect activated memory size. Undefined values require -// memsize parameter. -// -//======================================================== - -static unsigned int __devinit get_memsize(void) -{ - unsigned char tmp; - unsigned int k; - - if (memsize) - k = memsize * Kb; - else { - tmp = read3X4(CR1F) & 0x0F; - switch (tmp) { - case 0x03: - k = 1 * 1024 * 1024; - break; - case 0x07: - k = 2 * 1024 * 1024; - break; - case 0x0F: - k = 4 * 1024 * 1024; - break; - case 0x04: - k = 8 * 1024 * 1024; - break; - default: - k = 1 * 1024 * 1024; - output("Unknown memory size code %x in CR1F." - " We default to 1 Mb for now, please" - " do provide a memsize parameter!\n", tmp); - } - } - - if (verbosity > 0) - output("framebuffer size = %d Kb\n", k / Kb); - return k; -} - -//========================================================= -// -// Detect if a flat panel monitor connected to the special -// interface is active. Override is possible by fp and crt -// parameters. -// -//========================================================= - -static unsigned int __devinit get_displaytype(void) -{ - if (fp) - return DISPLAY_FP; - if (crt) - return DISPLAY_CRT; - return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; -} - -//===================================== -// -// Get native resolution of flat panel -// -//===================================== - -static int __devinit get_nativex(void) -{ - int x, y, tmp; - - if (nativex) - return nativex; - - tmp = (read3CE(GR52) >> 4) & 3; - - switch (tmp) { - case 0: x = 1280; y = 1024; - break; - case 2: x = 1024; y = 768; - break; - case 3: x = 800; y = 600; - break; - case 4: x = 1400; y = 1050; - break; - case 1: - default: - x = 640; y = 480; - break; - } - - if (verbosity > 0) - output("%dx%d flat panel found\n", x, y); - return x; -} - -static int __devinit cybla_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct fb_info *info; - struct cyblafb_par *par; - - info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev); - if (!info) - goto errout_alloc_info; - - info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL); - if (!info->pixmap.addr) { - output("allocation of pixmap buffer failed!\n"); - goto errout_alloc_pixmap; - } - info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4; - info->pixmap.buf_align = 4; - info->pixmap.access_align = 32; - info->pixmap.flags = FB_PIXMAP_SYSTEM; - info->pixmap.scan_align = 4; - - par = info->par; - par->ops = cyblafb_ops; - - info->fix = cyblafb_fix; - info->fbops = &par->ops; - info->fix = cyblafb_fix; - - if (pci_enable_device(dev)) { - output("could not enable device!\n"); - goto errout_enable; - } - // might already be requested by vga console or vesafb, - // so we do care about success - if (!request_region(0x3c0, 0x20, "cyblafb")) { - output("region 0x3c0/0x20 already reserved\n"); - vesafb |= 1; - - } - // - // Graphics Engine Registers - // - if (!request_region(GEBase, 0x100, "cyblafb")) { - output("region %#x/0x100 already reserved\n", GEBase); - vesafb |= 2; - } - - regdump(par); - - enable_mmio(); - - // setup MMIO region - info->fix.mmio_start = pci_resource_start(dev, 1); - info->fix.mmio_len = 0x20000; - - if (!request_mem_region(info->fix.mmio_start, - info->fix.mmio_len, "cyblafb")) { - output("request_mem_region failed for mmio region!\n"); - goto errout_mmio_reqmem; - } - - io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); - - if (!io_virt) { - output("ioremap failed for mmio region\n"); - goto errout_mmio_remap; - } - // setup framebuffer memory ... might already be requested - // by vesafb. Not to fail in case of an unsuccessful request - // is useful if both are loaded. - info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = get_memsize(); - - if (!request_mem_region(info->fix.smem_start, - info->fix.smem_len, "cyblafb")) { - output("region %#lx/%#x already reserved\n", - info->fix.smem_start, info->fix.smem_len); - vesafb |= 4; - } - - info->screen_base = ioremap_nocache(info->fix.smem_start, - info->fix.smem_len); - - if (!info->screen_base) { - output("ioremap failed for smem region\n"); - goto errout_smem_remap; - } - - displaytype = get_displaytype(); - - if (displaytype == DISPLAY_FP) - nativex = get_nativex(); - - info->flags = FBINFO_DEFAULT - | FBINFO_HWACCEL_COPYAREA - | FBINFO_HWACCEL_FILLRECT - | FBINFO_HWACCEL_IMAGEBLIT - | FBINFO_READS_FAST -// | FBINFO_PARTIAL_PAN_OK - | FBINFO_MISC_ALWAYS_SETPAR; - - info->pseudo_palette = par->pseudo_pal; - - if (getstartupmode(info)) - goto errout_findmode; - - fb_alloc_cmap(&info->cmap, 256, 0); - - if (register_framebuffer(info)) { - output("Could not register CyBla framebuffer\n"); - goto errout_register; - } - - pci_set_drvdata(dev, info); - - // - // normal exit and error paths - // - - return 0; - - errout_register: - errout_findmode: - iounmap(info->screen_base); - errout_smem_remap: - if (!(vesafb & 4)) - release_mem_region(info->fix.smem_start, info->fix.smem_len); - iounmap(io_virt); - errout_mmio_remap: - release_mem_region(info->fix.mmio_start, info->fix.mmio_len); - errout_mmio_reqmem: - if (!(vesafb & 1)) - release_region(0x3c0, 32); - errout_enable: - kfree(info->pixmap.addr); - errout_alloc_pixmap: - framebuffer_release(info); - errout_alloc_info: - output("CyblaFB version %s aborting init.\n", VERSION); - return -ENODEV; -} - -static void __devexit cybla_pci_remove(struct pci_dev *dev) -{ - struct fb_info *info = pci_get_drvdata(dev); - - unregister_framebuffer(info); - iounmap(io_virt); - iounmap(info->screen_base); - if (!(vesafb & 4)) - release_mem_region(info->fix.smem_start, info->fix.smem_len); - release_mem_region(info->fix.mmio_start, info->fix.mmio_len); - fb_dealloc_cmap(&info->cmap); - if (!(vesafb & 2)) - release_region(GEBase, 0x100); - if (!(vesafb & 1)) - release_region(0x3c0, 32); - kfree(info->pixmap.addr); - framebuffer_release(info); - output("CyblaFB version %s normal exit.\n", VERSION); -} - -// -// List of boards that we are trying to support -// -static struct pci_device_id cybla_devices[] = { - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, cybla_devices); - -static struct pci_driver cyblafb_pci_driver = { - .name = "cyblafb", - .id_table = cybla_devices, - .probe = cybla_pci_probe, - .remove = __devexit_p(cybla_pci_remove) -}; - -//============================================================= -// -// kernel command line example: -// -// video=cyblafb:1280x1024, bpp=16, ref=50 ... -// -// modprobe command line example: -// -// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ... -// -//============================================================= - -static int __devinit cyblafb_init(void) -{ -#ifndef MODULE - char *options = NULL; - char *opt; - - if (fb_get_options("cyblafb", &options)) - return -ENODEV; - - if (options && *options) - while ((opt = strsep(&options, ",")) != NULL) { - if (!*opt) - continue; - else if (!strncmp(opt, "bpp=", 4)) - bpp = simple_strtoul(opt + 4, NULL, 0); - else if (!strncmp(opt, "ref=", 4)) - ref = simple_strtoul(opt + 4, NULL, 0); - else if (!strncmp(opt, "fp", 2)) - displaytype = DISPLAY_FP; - else if (!strncmp(opt, "crt", 3)) - displaytype = DISPLAY_CRT; - else if (!strncmp(opt, "nativex=", 8)) - nativex = simple_strtoul(opt + 8, NULL, 0); - else if (!strncmp(opt, "center", 6)) - center = 1; - else if (!strncmp(opt, "stretch", 7)) - stretch = 1; - else if (!strncmp(opt, "pciwb=", 6)) - pciwb = simple_strtoul(opt + 6, NULL, 0); - else if (!strncmp(opt, "pcirb=", 6)) - pcirb = simple_strtoul(opt + 6, NULL, 0); - else if (!strncmp(opt, "pciwr=", 6)) - pciwr = simple_strtoul(opt + 6, NULL, 0); - else if (!strncmp(opt, "pcirr=", 6)) - pcirr = simple_strtoul(opt + 6, NULL, 0); - else if (!strncmp(opt, "memsize=", 8)) - memsize = simple_strtoul(opt + 8, NULL, 0); - else if (!strncmp(opt, "verbosity=", 10)) - verbosity = simple_strtoul(opt + 10, NULL, 0); - else - mode = opt; - } -#endif - output("CyblaFB version %s initializing\n", VERSION); - return pci_register_driver(&cyblafb_pci_driver); -} - -static void __exit cyblafb_exit(void) -{ - pci_unregister_driver(&cyblafb_pci_driver); -} - -module_init(cyblafb_init); -module_exit(cyblafb_exit); - -MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>"); -MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index daf9b81878a4..0c5b9a9fd56f 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -129,6 +129,8 @@ static int set_system(const struct dmi_system_id *id) screen_info.lfb_width = info->width; if (screen_info.lfb_height == 0) screen_info.lfb_height = info->height; + if (screen_info.orig_video_isVGA == 0) + screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; return 0; } @@ -374,9 +376,10 @@ static int __init efifb_init(void) int ret; char *option = NULL; + dmi_check_system(dmi_system_table); + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) return -ENODEV; - dmi_check_system(dmi_system_table); if (fb_get_options("efifb", &option)) return -ENODEV; diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 082026546aee..0a7a6679ee6e 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -85,8 +85,9 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); /* vm_ops->page_mkwrite handler */ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, - struct page *page) + struct vm_fault *vmf) { + struct page *page = vmf->page; struct fb_info *info = vma->vm_private_data; struct fb_deferred_io *fbdefio = info->fbdefio; struct page *cur; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index cfd9dce1ce0b..2ac32e6b5953 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -46,6 +46,17 @@ struct fb_info *registered_fb[FB_MAX] __read_mostly; int num_registered_fb __read_mostly; +int lock_fb_info(struct fb_info *info) +{ + mutex_lock(&info->lock); + if (!info->fbops) { + mutex_unlock(&info->lock); + return 0; + } + return 1; +} +EXPORT_SYMBOL(lock_fb_info); + /* * Helpers */ @@ -1086,13 +1097,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, return -EINVAL; con2fb.framebuffer = -1; event.data = &con2fb; - - if (!lock_fb_info(info)) - return -ENODEV; event.info = info; fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); - unlock_fb_info(info); - ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; break; case FBIOPUT_CON2FBMAP: @@ -1109,12 +1115,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, break; } event.data = &con2fb; - if (!lock_fb_info(info)) - return -ENODEV; event.info = info; - ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, - &event); - unlock_fb_info(info); + ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); break; case FBIOBLANK: if (!lock_fb_info(info)) diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index fb51197d1c98..f153c581cbd7 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1352,14 +1352,15 @@ static int fsl_diu_resume(struct of_device *ofdev) #endif /* CONFIG_PM */ /* Align to 64-bit(8-byte), 32-byte, etc. */ -static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, + u32 bytes_align) { u32 offset, ssize; u32 mask; dma_addr_t paddr = 0; ssize = size + bytes_align; - buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA | + buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA | __GFP_ZERO); if (!buf->vaddr) return -ENOMEM; @@ -1376,9 +1377,10 @@ static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) return 0; } -static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, + u32 bytes_align) { - dma_free_coherent(NULL, size + bytes_align, + dma_free_coherent(dev, size + bytes_align, buf->vaddr, (buf->paddr - buf->offset)); return; } @@ -1476,17 +1478,19 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, machine_data->monitor_port = monitor_port; /* Area descriptor memory pool aligns to 64-bit boundary */ - if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) + if (allocate_buf(&ofdev->dev, &pool.ad, + sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) return -ENOMEM; /* Get memory for Gamma Table - 32-byte aligned memory */ - if (allocate_buf(&pool.gamma, 768, 32)) { + if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) { ret = -ENOMEM; goto error; } /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ - if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) { + if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, + 32)) { ret = -ENOMEM; goto error; } @@ -1554,11 +1558,13 @@ error: i > 0; i--) uninstall_fb(machine_data->fsl_diu_info[i - 1]); if (pool.ad.vaddr) - free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + free_buf(&ofdev->dev, &pool.ad, + sizeof(struct diu_ad) * FSL_AOI_NUM, 8); if (pool.gamma.vaddr) - free_buf(&pool.gamma, 768, 32); + free_buf(&ofdev->dev, &pool.gamma, 768, 32); if (pool.cursor.vaddr) - free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, + 32); if (machine_data->dummy_aoi_virt) fsl_diu_free(machine_data->dummy_aoi_virt, 64); iounmap(dr.diu_reg); @@ -1584,11 +1590,13 @@ static int fsl_diu_remove(struct of_device *ofdev) for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) uninstall_fb(machine_data->fsl_diu_info[i - 1]); if (pool.ad.vaddr) - free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + free_buf(&ofdev->dev, &pool.ad, + sizeof(struct diu_ad) * FSL_AOI_NUM, 8); if (pool.gamma.vaddr) - free_buf(&pool.gamma, 768, 32); + free_buf(&ofdev->dev, &pool.gamma, 768, 32); if (pool.cursor.vaddr) - free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, + 32); if (machine_data->dummy_aoi_virt) fsl_diu_free(machine_data->dummy_aoi_virt, 64); iounmap(dr.diu_reg); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index fa1a512ce030..21b3692092f2 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -400,12 +400,12 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel, int16_t x_pos, int16_t y_pos) { - x_pos += mx3fb->h_start_width; - y_pos += mx3fb->v_start_width; - if (channel != IDMAC_SDC_0) return -EINVAL; + x_pos += mx3fb->h_start_width; + y_pos += mx3fb->v_start_width; + mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS); return 0; } @@ -491,11 +491,13 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, * 2^4 to get fractional part, as long as we stay under ~250MHz and on * i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz */ - dev_dbg(mx3fb->dev, "pixel clk = %d\n", pixel_clk); - ipu_clk = clk_get(mx3fb->dev, NULL); - div = clk_get_rate(ipu_clk) * 16 / pixel_clk; - clk_put(ipu_clk); + if (!IS_ERR(ipu_clk)) { + div = clk_get_rate(ipu_clk) * 16 / pixel_clk; + clk_put(ipu_clk); + } else { + div = 0; + } if (div < 0x40) { /* Divider less than 4 */ dev_dbg(mx3fb->dev, @@ -503,6 +505,9 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, div = 0x40; } + dev_dbg(mx3fb->dev, "pixel clk = %u, divider %u.%u\n", + pixel_clk, div >> 4, (div & 7) * 125); + spin_lock_irqsave(&mx3fb->lock, lock_flags); /* @@ -515,16 +520,16 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, /* DI settings */ old_conf = mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF) & 0x78FFFFFF; old_conf |= sig.datamask_en << DI_D3_DATAMSK_SHIFT | - sig.clksel_en << DI_D3_CLK_SEL_SHIFT | - sig.clkidle_en << DI_D3_CLK_IDLE_SHIFT; + sig.clksel_en << DI_D3_CLK_SEL_SHIFT | + sig.clkidle_en << DI_D3_CLK_IDLE_SHIFT; mx3fb_write_reg(mx3fb, old_conf, DI_DISP_IF_CONF); old_conf = mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL) & 0xE0FFFFFF; old_conf |= sig.data_pol << DI_D3_DATA_POL_SHIFT | - sig.clk_pol << DI_D3_CLK_POL_SHIFT | - sig.enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT | - sig.Hsync_pol << DI_D3_HSYNC_POL_SHIFT | - sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT; + sig.clk_pol << DI_D3_CLK_POL_SHIFT | + sig.enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT | + sig.Hsync_pol << DI_D3_HSYNC_POL_SHIFT | + sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT; mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL); switch (pixel_fmt) { @@ -721,7 +726,6 @@ static int mx3fb_set_par(struct fb_info *fbi) struct idmac_channel *ichan = mx3_fbi->idmac_channel; struct idmac_video_param *video = &ichan->params.video; struct scatterlist *sg = mx3_fbi->sg; - size_t screen_size; dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+'); @@ -745,12 +749,10 @@ static int mx3fb_set_par(struct fb_info *fbi) } } - screen_size = fbi->fix.line_length * fbi->var.yres; - sg_init_table(&sg[0], 1); sg_init_table(&sg[1], 1); - sg_dma_address(&sg[0]) = fbi->fix.smem_start; + sg_dma_address(&sg[0]) = fbi->fix.smem_start; sg_set_page(&sg[0], virt_to_page(fbi->screen_base), fbi->fix.smem_len, offset_in_page(fbi->screen_base)); @@ -927,7 +929,7 @@ static int mx3fb_setcolreg(unsigned int regno, unsigned int red, u32 val; int ret = 1; - dev_dbg(fbi->device, "%s\n", __func__); + dev_dbg(fbi->device, "%s, regno = %u\n", __func__, regno); mutex_lock(&mx3_fbi->mutex); /* @@ -973,9 +975,8 @@ static int mx3fb_blank(int blank, struct fb_info *fbi) struct mx3fb_info *mx3_fbi = fbi->par; struct mx3fb_data *mx3fb = mx3_fbi->mx3fb; - dev_dbg(fbi->device, "%s\n", __func__); - - dev_dbg(fbi->device, "blank = %d\n", blank); + dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__, + blank, fbi->screen_base, fbi->fix.smem_len); if (mx3_fbi->blank == blank) return 0; @@ -988,8 +989,11 @@ static int mx3fb_blank(int blank, struct fb_info *fbi) case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_NORMAL: - sdc_disable_channel(mx3_fbi); sdc_set_brightness(mx3fb, 0); + memset((char *)fbi->screen_base, 0, fbi->fix.smem_len); + /* Give LCD time to update - enough for 50 and 60 Hz */ + msleep(25); + sdc_disable_channel(mx3_fbi); break; case FB_BLANK_UNBLANK: sdc_enable_channel(mx3_fbi); @@ -1063,6 +1067,7 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, mutex_unlock(&mx3_fbi->mutex); dev_info(fbi->device, "Panning failed due to %s\n", ret < 0 ? "user interrupt" : "timeout"); + disable_irq(mx3_fbi->idmac_channel->eof_irq); return ret ? : -ETIMEDOUT; } @@ -1073,6 +1078,9 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, virt_to_page(fbi->screen_base + offset), fbi->fix.smem_len, offset_in_page(fbi->screen_base + offset)); + if (mx3_fbi->txd) + async_tx_ack(mx3_fbi->txd); + txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg + mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT); if (!txd) { @@ -1099,8 +1107,6 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, return -EIO; } - if (mx3_fbi->txd) - async_tx_ack(mx3_fbi->txd); mx3_fbi->txd = txd; fbi->var.xoffset = var->xoffset; @@ -1506,7 +1512,7 @@ static struct platform_driver mx3fb_driver = { * example: * video=mx3fb:bpp=16 */ -static int mx3fb_setup(void) +static int __init mx3fb_setup(void) { #ifndef MODULE char *opt, *options = NULL; diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index d9627b57eb4d..135ae18bfce8 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -362,6 +362,7 @@ int NVCommonSetup(struct fb_info *info) case 0x0186: case 0x0187: case 0x018D: + case 0x01D7: case 0x0228: case 0x0286: case 0x028C: diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index f132aab8c5de..c03f7f55c76d 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h @@ -5,7 +5,6 @@ #include <linux/types.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> -#include <linux/mutex.h> #include <video/vga.h> #define NV_ARCH_04 0x04 @@ -99,7 +98,6 @@ struct nvidia_par { RIVA_HW_STATE initial_state; RIVA_HW_STATE *CurrentState; struct vgastate vgastate; - struct mutex open_lock; u32 pseudo_palette[16]; struct pci_dev *pci_dev; u32 Architecture; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 9dbb5a5a267b..efe10ff86d63 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1004,15 +1004,12 @@ static int nvidiafb_open(struct fb_info *info, int user) { struct nvidia_par *par = info->par; - mutex_lock(&par->open_lock); - if (!par->open_count) { save_vga_x86(par); nvidia_save_vga(par, &par->initial_state); } par->open_count++; - mutex_unlock(&par->open_lock); return 0; } @@ -1021,8 +1018,6 @@ static int nvidiafb_release(struct fb_info *info, int user) struct nvidia_par *par = info->par; int err = 0; - mutex_lock(&par->open_lock); - if (!par->open_count) { err = -EINVAL; goto done; @@ -1035,7 +1030,6 @@ static int nvidiafb_release(struct fb_info *info, int user) par->open_count--; done: - mutex_unlock(&par->open_lock); return err; } @@ -1300,7 +1294,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, par = info->par; par->pci_dev = pd; - mutex_init(&par->open_lock); info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL); if (info->pixmap.addr == NULL) diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index f24df0b54e1c..8aa6e47202b9 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -742,7 +742,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) if (calc_reg_timing(sysclk, div) == 0) break; } - if (div > max_clk_div) + if (div >= max_clk_div) goto err; *extif_mem_div = div; @@ -752,7 +752,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) break; } - if (div > max_clk_div) + if (div >= max_clk_div) goto err; return 0; diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 1a49519dafa4..060d72fe57cb 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -338,7 +338,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) omapfb_rqueue_lock(fbdev); switch (blank) { - case VESA_NO_BLANKING: + case FB_BLANK_UNBLANK: if (fbdev->state == OMAPFB_SUSPENDED) { if (fbdev->ctrl->resume) fbdev->ctrl->resume(); @@ -349,7 +349,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) do_update = 1; } break; - case VESA_POWERDOWN: + case FB_BLANK_POWERDOWN: if (fbdev->state == OMAPFB_ACTIVE) { fbdev->panel->disable(fbdev->panel); if (fbdev->ctrl->suspend) @@ -1818,7 +1818,7 @@ static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) { struct omapfb_device *fbdev = platform_get_drvdata(pdev); - omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]); + omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]); return 0; } @@ -1828,7 +1828,7 @@ static int omapfb_resume(struct platform_device *pdev) { struct omapfb_device *fbdev = platform_get_drvdata(pdev); - omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]); + omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]); return 0; } diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index a7b01d2724b5..0726aecf3b7e 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -50,9 +50,22 @@ #define dbg(fmt, args...) do { } while (0) #endif -static const int __devinitconst s1d13xxxfb_revisions[] = { - S1D13506_CHIP_REV, /* Rev.4 on HP Jornada 7xx S1D13506 */ - S1D13806_CHIP_REV, /* Rev.7 on .. */ +/* + * List of card production ids + */ +static const int s1d13xxxfb_prod_ids[] = { + S1D13505_PROD_ID, + S1D13506_PROD_ID, + S1D13806_PROD_ID, +}; + +/* + * List of card strings + */ +static const char *s1d13xxxfb_prod_names[] = { + "S1D13505", + "S1D13506", + "S1D13806", }; /* @@ -377,7 +390,6 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } - /* framebuffer information structures */ static struct fb_ops s1d13xxxfb_fbops = { @@ -544,7 +556,7 @@ s1d13xxxfb_probe(struct platform_device *pdev) struct s1d13xxxfb_pdata *pdata = NULL; int ret = 0; int i; - u8 revision; + u8 revision, prod_id; dbg("probe called: device is %p\n", pdev); @@ -613,19 +625,31 @@ s1d13xxxfb_probe(struct platform_device *pdev) goto bail; } - revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2; - + /* production id is top 6 bits */ + prod_id = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2; + /* revision id is lower 2 bits */ + revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) & 0x3; ret = -ENODEV; - for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) { - if (revision == s1d13xxxfb_revisions[i]) + for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_prod_ids); i++) { + if (prod_id == s1d13xxxfb_prod_ids[i]) { + /* looks like we got it in our list */ + default_par->prod_id = prod_id; + default_par->revision = revision; ret = 0; + break; + } } - if (!ret) + if (!ret) { + printk(KERN_INFO PFX "chip production id %i = %s\n", + prod_id, s1d13xxxfb_prod_names[i]); printk(KERN_INFO PFX "chip revision %i\n", revision); - else { - printk(KERN_INFO PFX "unknown chip revision %i\n", revision); + } else { + printk(KERN_INFO PFX + "unknown chip production id %i, revision %i\n", + prod_id, revision); + printk(KERN_INFO PFX "please contant maintainer\n"); goto bail; } diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c new file mode 100644 index 000000000000..5e9c6302433b --- /dev/null +++ b/drivers/video/s3c-fb.c @@ -0,0 +1,1036 @@ +/* linux/drivers/video/s3c-fb.c + * + * Copyright 2008 Openmoko Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Samsung SoC Framebuffer 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/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/gfp.h> +#include <linux/clk.h> +#include <linux/fb.h> +#include <linux/io.h> + +#include <mach/map.h> +#include <mach/regs-fb.h> +#include <plat/fb.h> + +/* This driver will export a number of framebuffer interfaces depending + * on the configuration passed in via the platform data. Each fb instance + * maps to a hardware window. Currently there is no support for runtime + * setting of the alpha-blending functions that each window has, so only + * window 0 is actually useful. + * + * Window 0 is treated specially, it is used for the basis of the LCD + * output timings and as the control for the output power-down state. +*/ + +/* note, some of the functions that get called are derived from including + * <mach/regs-fb.h> as they are specific to the architecture that the code + * is being built for. +*/ + +#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE +#undef writel +#define writel(v, r) do { \ + printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ + __raw_writel(v, r); } while(0) +#endif /* FB_S3C_DEBUG_REGWRITE */ + +struct s3c_fb; + +/** + * struct s3c_fb_win - per window private data for each framebuffer. + * @windata: The platform data supplied for the window configuration. + * @parent: The hardware that this window is part of. + * @fbinfo: Pointer pack to the framebuffer info for this window. + * @palette_buffer: Buffer/cache to hold palette entries. + * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/ + * @index: The window number of this window. + * @palette: The bitfields for changing r/g/b into a hardware palette entry. + */ +struct s3c_fb_win { + struct s3c_fb_pd_win *windata; + struct s3c_fb *parent; + struct fb_info *fbinfo; + struct s3c_fb_palette palette; + + u32 *palette_buffer; + u32 pseudo_palette[16]; + unsigned int index; +}; + +/** + * struct s3c_fb - overall hardware state of the hardware + * @dev: The device that we bound to, for printing, etc. + * @regs_res: The resource we claimed for the IO registers. + * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. + * @regs: The mapped hardware registers. + * @enabled: A bitmask of enabled hardware windows. + * @pdata: The platform configuration data passed with the device. + * @windows: The hardware windows that have been claimed. + */ +struct s3c_fb { + struct device *dev; + struct resource *regs_res; + struct clk *bus_clk; + void __iomem *regs; + + unsigned char enabled; + + struct s3c_fb_platdata *pdata; + struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; +}; + +/** + * s3c_fb_win_has_palette() - determine if a mode has a palette + * @win: The window number being queried. + * @bpp: The number of bits per pixel to test. + * + * Work out if the given window supports palletised data at the specified bpp. + */ +static int s3c_fb_win_has_palette(unsigned int win, unsigned int bpp) +{ + return s3c_fb_win_pal_size(win) <= (1 << bpp); +} + +/** + * s3c_fb_check_var() - framebuffer layer request to verify a given mode. + * @var: The screen information to verify. + * @info: The framebuffer device. + * + * Framebuffer layer call to verify the given information and allow us to + * update various information depending on the hardware capabilities. + */ +static int s3c_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct s3c_fb_win *win = info->par; + struct s3c_fb_pd_win *windata = win->windata; + struct s3c_fb *sfb = win->parent; + + dev_dbg(sfb->dev, "checking parameters\n"); + + var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres); + var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres); + + if (!s3c_fb_validate_win_bpp(win->index, var->bits_per_pixel)) { + dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", + win->index, var->bits_per_pixel); + return -EINVAL; + } + + /* always ensure these are zero, for drop through cases below */ + var->transp.offset = 0; + var->transp.length = 0; + + switch (var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + if (!s3c_fb_win_has_palette(win->index, var->bits_per_pixel)) { + /* non palletised, A:1,R:2,G:3,B:2 mode */ + var->red.offset = 4; + var->green.offset = 2; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 3; + var->blue.length = 2; + var->transp.offset = 7; + var->transp.length = 1; + } else { + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + } + break; + + case 19: + /* 666 with one bit alpha/transparency */ + var->transp.offset = 18; + var->transp.length = 1; + case 18: + var->bits_per_pixel = 32; + + /* 666 format */ + var->red.offset = 12; + var->green.offset = 6; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + + case 16: + /* 16 bpp, 565 format */ + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + + case 28: + case 25: + var->transp.length = var->bits_per_pixel - 24; + var->transp.offset = 24; + /* drop through */ + case 24: + /* our 24bpp is unpacked, so 32bpp */ + var->bits_per_pixel = 32; + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + default: + dev_err(sfb->dev, "invalid bpp\n"); + } + + dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); + return 0; +} + +/** + * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. + * @sfb: The hardware state. + * @pixclock: The pixel clock wanted, in picoseconds. + * + * Given the specified pixel clock, work out the necessary divider to get + * close to the output frequency. + */ +static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) +{ + unsigned long clk = clk_get_rate(sfb->bus_clk); + unsigned long long tmp; + unsigned int result; + + tmp = (unsigned long long)clk; + tmp *= pixclk; + + do_div(tmp, 1000000000UL); + result = (unsigned int)tmp / 1000; + + dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", + pixclk, clk, result, clk / result); + + return result; +} + +/** + * s3c_fb_align_word() - align pixel count to word boundary + * @bpp: The number of bits per pixel + * @pix: The value to be aligned. + * + * Align the given pixel count so that it will start on an 32bit word + * boundary. + */ +static int s3c_fb_align_word(unsigned int bpp, unsigned int pix) +{ + int pix_per_word; + + if (bpp > 16) + return pix; + + pix_per_word = (8 * 32) / bpp; + return ALIGN(pix, pix_per_word); +} + +/** + * s3c_fb_set_par() - framebuffer request to set new framebuffer state. + * @info: The framebuffer to change. + * + * Framebuffer layer request to set a new mode for the specified framebuffer + */ +static int s3c_fb_set_par(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct s3c_fb_win *win = info->par; + struct s3c_fb *sfb = win->parent; + void __iomem *regs = sfb->regs; + int win_no = win->index; + u32 data; + u32 pagewidth; + int clkdiv; + + dev_dbg(sfb->dev, "setting framebuffer parameters\n"); + + switch (var->bits_per_pixel) { + case 32: + case 24: + case 16: + case 12: + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 8: + if (s3c_fb_win_has_palette(win_no, 8)) + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + default: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + } + + info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; + + /* disable the window whilst we update it */ + writel(0, regs + WINCON(win_no)); + + /* use window 0 as the basis for the lcd output timings */ + + if (win_no == 0) { + clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); + + data = sfb->pdata->vidcon0; + data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); + + if (clkdiv > 1) + data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; + else + data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ + + /* write the timing data to the panel */ + + data |= VIDCON0_ENVID | VIDCON0_ENVID_F; + writel(data, regs + VIDCON0); + + data = VIDTCON0_VBPD(var->upper_margin - 1) | + VIDTCON0_VFPD(var->lower_margin - 1) | + VIDTCON0_VSPW(var->vsync_len - 1); + + writel(data, regs + VIDTCON0); + + data = VIDTCON1_HBPD(var->left_margin - 1) | + VIDTCON1_HFPD(var->right_margin - 1) | + VIDTCON1_HSPW(var->hsync_len - 1); + + writel(data, regs + VIDTCON1); + + data = VIDTCON2_LINEVAL(var->yres - 1) | + VIDTCON2_HOZVAL(var->xres - 1); + writel(data, regs + VIDTCON2); + } + + /* write the buffer address */ + + writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no)); + + data = info->fix.smem_start + info->fix.line_length * var->yres; + writel(data, regs + VIDW_BUF_END(win_no)); + + pagewidth = (var->xres * var->bits_per_pixel) >> 3; + data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | + VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); + writel(data, regs + VIDW_BUF_SIZE(win_no)); + + /* write 'OSD' registers to control position of framebuffer */ + + data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); + writel(data, regs + VIDOSD_A(win_no)); + + data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, + var->xres - 1)) | + VIDOSDxB_BOTRIGHT_Y(var->yres - 1); + + writel(data, regs + VIDOSD_B(win_no)); + + data = var->xres * var->yres; + if (s3c_fb_has_osd_d(win_no)) { + writel(data, regs + VIDOSD_D(win_no)); + writel(0, regs + VIDOSD_C(win_no)); + } else + writel(data, regs + VIDOSD_C(win_no)); + + data = WINCONx_ENWIN; + + /* note, since we have to round up the bits-per-pixel, we end up + * relying on the bitfield information for r/g/b/a to work out + * exactly which mode of operation is intended. */ + + switch (var->bits_per_pixel) { + case 1: + data |= WINCON0_BPPMODE_1BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_4WORD; + break; + case 2: + data |= WINCON0_BPPMODE_2BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_8WORD; + break; + case 4: + data |= WINCON0_BPPMODE_4BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_8WORD; + break; + case 8: + if (var->transp.length != 0) + data |= WINCON1_BPPMODE_8BPP_1232; + else + data |= WINCON0_BPPMODE_8BPP_PALETTE; + data |= WINCONx_BURSTLEN_8WORD; + data |= WINCONx_BYTSWP; + break; + case 16: + if (var->transp.length != 0) + data |= WINCON1_BPPMODE_16BPP_A1555; + else + data |= WINCON0_BPPMODE_16BPP_565; + data |= WINCONx_HAWSWP; + data |= WINCONx_BURSTLEN_16WORD; + break; + case 24: + case 32: + if (var->red.length == 6) { + if (var->transp.length != 0) + data |= WINCON1_BPPMODE_19BPP_A1666; + else + data |= WINCON1_BPPMODE_18BPP_666; + } else if (var->transp.length != 0) + data |= WINCON1_BPPMODE_25BPP_A1888; + else + data |= WINCON0_BPPMODE_24BPP_888; + + data |= WINCONx_BURSTLEN_16WORD; + break; + } + + writel(data, regs + WINCON(win_no)); + writel(0x0, regs + WINxMAP(win_no)); + + return 0; +} + +/** + * s3c_fb_update_palette() - set or schedule a palette update. + * @sfb: The hardware information. + * @win: The window being updated. + * @reg: The palette index being changed. + * @value: The computed palette value. + * + * Change the value of a palette register, either by directly writing to + * the palette (this requires the palette RAM to be disconnected from the + * hardware whilst this is in progress) or schedule the update for later. + * + * At the moment, since we have no VSYNC interrupt support, we simply set + * the palette entry directly. + */ +static void s3c_fb_update_palette(struct s3c_fb *sfb, + struct s3c_fb_win *win, + unsigned int reg, + u32 value) +{ + void __iomem *palreg; + u32 palcon; + + palreg = sfb->regs + s3c_fb_pal_reg(win->index, reg); + + dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n", + __func__, win->index, reg, palreg, value); + + win->palette_buffer[reg] = value; + + palcon = readl(sfb->regs + WPALCON); + writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON); + + if (s3c_fb_pal_is16(win->index)) + writew(value, palreg); + else + writel(value, palreg); + + writel(palcon, sfb->regs + WPALCON); +} + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +/** + * s3c_fb_setcolreg() - framebuffer layer request to change palette. + * @regno: The palette index to change. + * @red: The red field for the palette data. + * @green: The green field for the palette data. + * @blue: The blue field for the palette data. + * @trans: The transparency (alpha) field for the palette data. + * @info: The framebuffer being changed. + */ +static int s3c_fb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct s3c_fb_win *win = info->par; + struct s3c_fb *sfb = win->parent; + unsigned int val; + + dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", + __func__, win->index, regno, red, green, blue); + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* true-colour, use pseudo-palette */ + + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); + + pal[regno] = val; + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + if (regno < s3c_fb_win_pal_size(win->index)) { + val = chan_to_field(red, &win->palette.r); + val |= chan_to_field(green, &win->palette.g); + val |= chan_to_field(blue, &win->palette.b); + + s3c_fb_update_palette(sfb, win, regno, val); + } + + break; + + default: + return 1; /* unknown type */ + } + + return 0; +} + +/** + * s3c_fb_enable() - Set the state of the main LCD output + * @sfb: The main framebuffer state. + * @enable: The state to set. + */ +static void s3c_fb_enable(struct s3c_fb *sfb, int enable) +{ + u32 vidcon0 = readl(sfb->regs + VIDCON0); + + if (enable) + vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; + else { + /* see the note in the framebuffer datasheet about + * why you cannot take both of these bits down at the + * same time. */ + + if (!(vidcon0 & VIDCON0_ENVID)) + return; + + vidcon0 |= VIDCON0_ENVID; + vidcon0 &= ~VIDCON0_ENVID_F; + } + + writel(vidcon0, sfb->regs + VIDCON0); +} + +/** + * s3c_fb_blank() - blank or unblank the given window + * @blank_mode: The blank state from FB_BLANK_* + * @info: The framebuffer to blank. + * + * Framebuffer layer request to change the power state. + */ +static int s3c_fb_blank(int blank_mode, struct fb_info *info) +{ + struct s3c_fb_win *win = info->par; + struct s3c_fb *sfb = win->parent; + unsigned int index = win->index; + u32 wincon; + + dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); + + wincon = readl(sfb->regs + WINCON(index)); + + switch (blank_mode) { + case FB_BLANK_POWERDOWN: + wincon &= ~WINCONx_ENWIN; + sfb->enabled &= ~(1 << index); + /* fall through to FB_BLANK_NORMAL */ + + case FB_BLANK_NORMAL: + /* disable the DMA and display 0x0 (black) */ + writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), + sfb->regs + WINxMAP(index)); + break; + + case FB_BLANK_UNBLANK: + writel(0x0, sfb->regs + WINxMAP(index)); + wincon |= WINCONx_ENWIN; + sfb->enabled |= (1 << index); + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + default: + return 1; + } + + writel(wincon, sfb->regs + WINCON(index)); + + /* Check the enabled state to see if we need to be running the + * main LCD interface, as if there are no active windows then + * it is highly likely that we also do not need to output + * anything. + */ + + /* We could do something like the following code, but the current + * system of using framebuffer events means that we cannot make + * the distinction between just window 0 being inactive and all + * the windows being down. + * + * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); + */ + + /* we're stuck with this until we can do something about overriding + * the power control using the blanking event for a single fb. + */ + if (index == 0) + s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); + + return 0; +} + +static struct fb_ops s3c_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = s3c_fb_check_var, + .fb_set_par = s3c_fb_set_par, + .fb_blank = s3c_fb_blank, + .fb_setcolreg = s3c_fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +/** + * s3c_fb_alloc_memory() - allocate display memory for framebuffer window + * @sfb: The base resources for the hardware. + * @win: The window to initialise memory for. + * + * Allocate memory for the given framebuffer. + */ +static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb, + struct s3c_fb_win *win) +{ + struct s3c_fb_pd_win *windata = win->windata; + unsigned int real_size, virt_size, size; + struct fb_info *fbi = win->fbinfo; + dma_addr_t map_dma; + + dev_dbg(sfb->dev, "allocating memory for display\n"); + + real_size = windata->win_mode.xres * windata->win_mode.yres; + virt_size = windata->virtual_x * windata->virtual_y; + + dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", + real_size, windata->win_mode.xres, windata->win_mode.yres, + virt_size, windata->virtual_x, windata->virtual_y); + + size = (real_size > virt_size) ? real_size : virt_size; + size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp; + size /= 8; + + fbi->fix.smem_len = size; + size = PAGE_ALIGN(size); + + dev_dbg(sfb->dev, "want %u bytes for window\n", size); + + fbi->screen_base = dma_alloc_writecombine(sfb->dev, size, + &map_dma, GFP_KERNEL); + if (!fbi->screen_base) + return -ENOMEM; + + dev_dbg(sfb->dev, "mapped %x to %p\n", + (unsigned int)map_dma, fbi->screen_base); + + memset(fbi->screen_base, 0x0, size); + fbi->fix.smem_start = map_dma; + + return 0; +} + +/** + * s3c_fb_free_memory() - free the display memory for the given window + * @sfb: The base resources for the hardware. + * @win: The window to free the display memory for. + * + * Free the display memory allocated by s3c_fb_alloc_memory(). + */ +static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) +{ + struct fb_info *fbi = win->fbinfo; + + dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len), + fbi->screen_base, fbi->fix.smem_start); +} + +/** + * s3c_fb_release_win() - release resources for a framebuffer window. + * @win: The window to cleanup the resources for. + * + * Release the resources that where claimed for the hardware window, + * such as the framebuffer instance and any memory claimed for it. + */ +static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) +{ + fb_dealloc_cmap(&win->fbinfo->cmap); + unregister_framebuffer(win->fbinfo); + s3c_fb_free_memory(sfb, win); +} + +/** + * s3c_fb_probe_win() - register an hardware window + * @sfb: The base resources for the hardware + * @res: Pointer to where to place the resultant window. + * + * Allocate and do the basic initialisation for one of the hardware's graphics + * windows. + */ +static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, + struct s3c_fb_win **res) +{ + struct fb_var_screeninfo *var; + struct fb_videomode *initmode; + struct s3c_fb_pd_win *windata; + struct s3c_fb_win *win; + struct fb_info *fbinfo; + int palette_size; + int ret; + + dev_dbg(sfb->dev, "probing window %d\n", win_no); + + palette_size = s3c_fb_win_pal_size(win_no); + + fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) + + palette_size * sizeof(u32), sfb->dev); + if (!fbinfo) { + dev_err(sfb->dev, "failed to allocate framebuffer\n"); + return -ENOENT; + } + + windata = sfb->pdata->win[win_no]; + initmode = &windata->win_mode; + + WARN_ON(windata->max_bpp == 0); + WARN_ON(windata->win_mode.xres == 0); + WARN_ON(windata->win_mode.yres == 0); + + win = fbinfo->par; + var = &fbinfo->var; + win->fbinfo = fbinfo; + win->parent = sfb; + win->windata = windata; + win->index = win_no; + win->palette_buffer = (u32 *)(win + 1); + + ret = s3c_fb_alloc_memory(sfb, win); + if (ret) { + dev_err(sfb->dev, "failed to allocate display memory\n"); + goto err_framebuffer; + } + + /* setup the r/b/g positions for the window's palette */ + s3c_fb_init_palette(win_no, &win->palette); + + /* setup the initial video mode from the window */ + fb_videomode_to_var(&fbinfo->var, initmode); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + fbinfo->var.bits_per_pixel = windata->default_bpp; + fbinfo->fbops = &s3c_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + fbinfo->pseudo_palette = &win->pseudo_palette; + + /* prepare to actually start the framebuffer */ + + ret = s3c_fb_check_var(&fbinfo->var, fbinfo); + if (ret < 0) { + dev_err(sfb->dev, "check_var failed on initial video params\n"); + goto err_alloc_mem; + } + + /* create initial colour map */ + + ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1); + if (ret == 0) + fb_set_cmap(&fbinfo->cmap, fbinfo); + else + dev_err(sfb->dev, "failed to allocate fb cmap\n"); + + s3c_fb_set_par(fbinfo); + + dev_dbg(sfb->dev, "about to register framebuffer\n"); + + /* run the check_var and set_par on our configuration. */ + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + dev_err(sfb->dev, "failed to register framebuffer\n"); + goto err_alloc_mem; + } + + *res = win; + dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id); + + return 0; + +err_alloc_mem: + s3c_fb_free_memory(sfb, win); + +err_framebuffer: + unregister_framebuffer(fbinfo); + return ret; +} + +/** + * s3c_fb_clear_win() - clear hardware window registers. + * @sfb: The base resources for the hardware. + * @win: The window to process. + * + * Reset the specific window registers to a known state. + */ +static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) +{ + void __iomem *regs = sfb->regs; + + writel(0, regs + WINCON(win)); + writel(0xffffff, regs + WxKEYCONy(win, 0)); + writel(0xffffff, regs + WxKEYCONy(win, 1)); + + writel(0, regs + VIDOSD_A(win)); + writel(0, regs + VIDOSD_B(win)); + writel(0, regs + VIDOSD_C(win)); +} + +static int __devinit s3c_fb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct s3c_fb_platdata *pd; + struct s3c_fb *sfb; + struct resource *res; + int win; + int ret = 0; + + pd = pdev->dev.platform_data; + if (!pd) { + dev_err(dev, "no platform data specified\n"); + return -EINVAL; + } + + sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL); + if (!sfb) { + dev_err(dev, "no memory for framebuffers\n"); + return -ENOMEM; + } + + sfb->dev = dev; + sfb->pdata = pd; + + sfb->bus_clk = clk_get(dev, "lcd"); + if (IS_ERR(sfb->bus_clk)) { + dev_err(dev, "failed to get bus clock\n"); + goto err_sfb; + } + + clk_enable(sfb->bus_clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to find registers\n"); + ret = -ENOENT; + goto err_clk; + } + + sfb->regs_res = request_mem_region(res->start, resource_size(res), + dev_name(dev)); + if (!sfb->regs_res) { + dev_err(dev, "failed to claim register region\n"); + ret = -ENOENT; + goto err_clk; + } + + sfb->regs = ioremap(res->start, resource_size(res)); + if (!sfb->regs) { + dev_err(dev, "failed to map registers\n"); + ret = -ENXIO; + goto err_req_region; + } + + dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); + + /* setup gpio and output polarity controls */ + + pd->setup_gpio(); + + writel(pd->vidcon1, sfb->regs + VIDCON1); + + /* zero all windows before we do anything */ + + for (win = 0; win < S3C_FB_MAX_WIN; win++) + s3c_fb_clear_win(sfb, win); + + /* we have the register setup, start allocating framebuffers */ + + for (win = 0; win < S3C_FB_MAX_WIN; win++) { + if (!pd->win[win]) + continue; + + ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]); + if (ret < 0) { + dev_err(dev, "failed to create window %d\n", win); + for (; win >= 0; win--) + s3c_fb_release_win(sfb, sfb->windows[win]); + goto err_ioremap; + } + } + + platform_set_drvdata(pdev, sfb); + + return 0; + +err_ioremap: + iounmap(sfb->regs); + +err_req_region: + release_resource(sfb->regs_res); + kfree(sfb->regs_res); + +err_clk: + clk_disable(sfb->bus_clk); + clk_put(sfb->bus_clk); + +err_sfb: + kfree(sfb); + return ret; +} + +/** + * s3c_fb_remove() - Cleanup on module finalisation + * @pdev: The platform device we are bound to. + * + * Shutdown and then release all the resources that the driver allocated + * on initialisation. + */ +static int __devexit s3c_fb_remove(struct platform_device *pdev) +{ + struct s3c_fb *sfb = platform_get_drvdata(pdev); + int win; + + for (win = 0; win <= S3C_FB_MAX_WIN; win++) + s3c_fb_release_win(sfb, sfb->windows[win]); + + iounmap(sfb->regs); + + clk_disable(sfb->bus_clk); + clk_put(sfb->bus_clk); + + release_resource(sfb->regs_res); + kfree(sfb->regs_res); + + kfree(sfb); + + return 0; +} + +#ifdef CONFIG_PM +static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct s3c_fb *sfb = platform_get_drvdata(pdev); + struct s3c_fb_win *win; + int win_no; + + for (win_no = S3C_FB_MAX_WIN; win_no >= 0; win_no--) { + win = sfb->windows[win_no]; + if (!win) + continue; + + /* use the blank function to push into power-down */ + s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); + } + + clk_disable(sfb->bus_clk); + return 0; +} + +static int s3c_fb_resume(struct platform_device *pdev) +{ + struct s3c_fb *sfb = platform_get_drvdata(pdev); + struct s3c_fb_win *win; + int win_no; + + clk_enable(sfb->bus_clk); + + for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { + win = sfb->windows[win_no]; + if (!win) + continue; + + dev_dbg(&pdev->dev, "resuming window %d\n", win_no); + s3c_fb_set_par(win->fbinfo); + } + + return 0; +} +#else +#define s3c_fb_suspend NULL +#define s3c_fb_resume NULL +#endif + +static struct platform_driver s3c_fb_driver = { + .probe = s3c_fb_probe, + .remove = s3c_fb_remove, + .suspend = s3c_fb_suspend, + .resume = s3c_fb_resume, + .driver = { + .name = "s3c-fb", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c_fb_init(void) +{ + return platform_driver_register(&s3c_fb_driver); +} + +static void __exit s3c_fb_cleanup(void) +{ + platform_driver_unregister(&s3c_fb_driver); +} + +module_init(s3c_fb_init); +module_exit(s3c_fb_cleanup); + +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); +MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c-fb"); diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index f5252c2552fd..bba53714a7b1 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -837,6 +837,8 @@ static int sgivwfb_remove(struct platform_device *dev) iounmap(par->regs); iounmap(info->screen_base); release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); } return 0; } diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index df5336561d13..a439159204a8 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -795,8 +795,9 @@ static int __devinit xxxfb_probe(struct pci_dev *dev, if (!retval || retval == 4) return -EINVAL; - /* This has to been done !!! */ - fb_alloc_cmap(&info->cmap, cmap_len, 0); + /* This has to be done! */ + if (fb_alloc_cmap(&info->cmap, cmap_len, 0)) + return -ENOMEM; /* * The following is done in the case of having hardware with a static @@ -820,8 +821,10 @@ static int __devinit xxxfb_probe(struct pci_dev *dev, */ /* xxxfb_set_par(info); */ - if (register_framebuffer(info) < 0) + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); return -EINVAL; + } printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); pci_set_drvdata(dev, info); /* or platform_set_drvdata(pdev, info) */ diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index dcd98793d568..eb5d73a06702 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -1525,7 +1525,10 @@ static int sm501fb_init_fb(struct fb_info *fb, } /* initialise and set the palette */ - fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0); + if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) { + dev_err(info->dev, "failed to allocate cmap memory\n"); + return -ENOMEM; + } fb_set_cmap(&fb->cmap, fb); ret = (fb->fbops->fb_check_var)(&fb->var, fb); diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 5b11a00f49bc..609d0a521ca2 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -1421,13 +1421,16 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, goto fail; } - fb_alloc_cmap(&info->cmap, 256, 0); + if (fb_alloc_cmap(&info->cmap, 256, 0)) { + printk(KERN_ERR "sstfb: can't alloc cmap memory.\n"); + goto fail; + } /* register fb */ info->device = &pdev->dev; if (register_framebuffer(info) < 0) { printk(KERN_ERR "sstfb: can't register framebuffer.\n"); - goto fail; + goto fail_register; } sstfb_clear_screen(info); @@ -1441,8 +1444,9 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, return 0; -fail: +fail_register: fb_dealloc_cmap(&info->cmap); +fail: iounmap(info->screen_base); fail_fb_remap: iounmap(par->mmio_vbase); diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index 166481402412..eabaad765aeb 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -1262,24 +1262,25 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) info->flags = FBINFO_DEFAULT; info->pseudo_palette = &fb->pseudo_palette; - /* This has to been done !!! */ - fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); + /* This has to be done !!! */ + if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0)) + goto out_err1; stifb_init_display(fb); if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) { printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", fix->smem_start, fix->smem_start+fix->smem_len); - goto out_err1; + goto out_err2; } if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", fix->mmio_start, fix->mmio_start+fix->mmio_len); - goto out_err2; + goto out_err3; } if (register_framebuffer(&fb->info) < 0) - goto out_err3; + goto out_err4; sti->info = info; /* save for unregister_framebuffer() */ @@ -1297,13 +1298,14 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) return 0; -out_err3: +out_err4: release_mem_region(fix->mmio_start, fix->mmio_len); -out_err2: +out_err3: release_mem_region(fix->smem_start, fix->smem_len); +out_err2: + fb_dealloc_cmap(&info->cmap); out_err1: iounmap(info->screen_base); - fb_dealloc_cmap(&info->cmap); out_err0: kfree(fb); return -ENXIO; diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c index c2ba51b7ea18..18b950706cad 100644 --- a/drivers/video/sunxvr500.c +++ b/drivers/video/sunxvr500.c @@ -349,11 +349,14 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev, if (err < 0) { printk(KERN_ERR "e3d: Could not register framebuffer %s\n", pci_name(pdev)); - goto err_unmap_fb; + goto err_free_cmap; } return 0; +err_free_cmap: + fb_dealloc_cmap(&info->cmap); + err_unmap_fb: iounmap(ep->fb_base); @@ -389,6 +392,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev) pci_release_region(pdev, 0); pci_release_region(pdev, 1); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); pci_disable_device(pdev); diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 14bd3f3680b8..89f231dc443f 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -10,6 +10,12 @@ * Created : Thu Sep 23 18:17:43 1999, hmallat * Last modified: Tue Nov 2 21:19:47 1999, hmallat * + * I2C part copied from the i2c-voodoo3.c driver by: + * Frodo Looijaard <frodol@dds.nl>, + * Philip Edelbrock <phil@netroedge.com>, + * Ralph Metzler <rjkm@thp.uni-koeln.de>, and + * Mark D. Studebaker <mdsxyz123@yahoo.com> + * * Lots of the information here comes from the Daryll Strauss' Banshee * patches to the XF86 server, and the rest comes from the 3dfx * Banshee specification. I'm very much indebted to Daryll for his @@ -481,6 +487,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) return -EINVAL; } + if (info->monspecs.hfmax && info->monspecs.vfmax && + info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) { + DPRINTK("mode outside monitor's specs\n"); + return -EINVAL; + } + var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); @@ -1167,6 +1179,207 @@ static struct fb_ops tdfxfb_ops = { #endif }; +#ifdef CONFIG_FB_3DFX_I2C +/* The voo GPIO registers don't have individual masks for each bit + so we always have to read before writing. */ + +static void tdfxfb_i2c_setscl(void *data, int val) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + unsigned int r; + + r = tdfx_inl(par, VIDSERPARPORT); + if (val) + r |= I2C_SCL_OUT; + else + r &= ~I2C_SCL_OUT; + tdfx_outl(par, VIDSERPARPORT, r); + tdfx_inl(par, VIDSERPARPORT); /* flush posted write */ +} + +static void tdfxfb_i2c_setsda(void *data, int val) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + unsigned int r; + + r = tdfx_inl(par, VIDSERPARPORT); + if (val) + r |= I2C_SDA_OUT; + else + r &= ~I2C_SDA_OUT; + tdfx_outl(par, VIDSERPARPORT, r); + tdfx_inl(par, VIDSERPARPORT); /* flush posted write */ +} + +/* The GPIO pins are open drain, so the pins always remain outputs. + We rely on the i2c-algo-bit routines to set the pins high before + reading the input from other chips. */ + +static int tdfxfb_i2c_getscl(void *data) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + + return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SCL_IN)); +} + +static int tdfxfb_i2c_getsda(void *data) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + + return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SDA_IN)); +} + +static void tdfxfb_ddc_setscl(void *data, int val) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + unsigned int r; + + r = tdfx_inl(par, VIDSERPARPORT); + if (val) + r |= DDC_SCL_OUT; + else + r &= ~DDC_SCL_OUT; + tdfx_outl(par, VIDSERPARPORT, r); + tdfx_inl(par, VIDSERPARPORT); /* flush posted write */ +} + +static void tdfxfb_ddc_setsda(void *data, int val) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + unsigned int r; + + r = tdfx_inl(par, VIDSERPARPORT); + if (val) + r |= DDC_SDA_OUT; + else + r &= ~DDC_SDA_OUT; + tdfx_outl(par, VIDSERPARPORT, r); + tdfx_inl(par, VIDSERPARPORT); /* flush posted write */ +} + +static int tdfxfb_ddc_getscl(void *data) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + + return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SCL_IN)); +} + +static int tdfxfb_ddc_getsda(void *data) +{ + struct tdfxfb_i2c_chan *chan = data; + struct tdfx_par *par = chan->par; + + return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN)); +} + +static int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan, + const char *name, struct device *dev) +{ + int rc; + + strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); + chan->adapter.owner = THIS_MODULE; + chan->adapter.class = I2C_CLASS_DDC; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = dev; + chan->algo.setsda = tdfxfb_ddc_setsda; + chan->algo.setscl = tdfxfb_ddc_setscl; + chan->algo.getsda = tdfxfb_ddc_getsda; + chan->algo.getscl = tdfxfb_ddc_getscl; + chan->algo.udelay = 10; + chan->algo.timeout = msecs_to_jiffies(500); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + DPRINTK("I2C bus %s registered.\n", name); + else + chan->par = NULL; + + return rc; +} + +static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, + const char *name, struct device *dev) +{ + int rc; + + strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); + chan->adapter.owner = THIS_MODULE; + chan->adapter.class = I2C_CLASS_TV_ANALOG; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = dev; + chan->algo.setsda = tdfxfb_i2c_setsda; + chan->algo.setscl = tdfxfb_i2c_setscl; + chan->algo.getsda = tdfxfb_i2c_getsda; + chan->algo.getscl = tdfxfb_i2c_getscl; + chan->algo.udelay = 10; + chan->algo.timeout = msecs_to_jiffies(500); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + DPRINTK("I2C bus %s registered.\n", name); + else + chan->par = NULL; + + return rc; +} + +static void __devinit tdfxfb_create_i2c_busses(struct fb_info *info) +{ + struct tdfx_par *par = info->par; + + tdfx_outl(par, VIDINFORMAT, 0x8160); + tdfx_outl(par, VIDSERPARPORT, 0xcffc0020); + + par->chan[0].par = par; + par->chan[1].par = par; + + tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->dev); + tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->dev); +} + +static void tdfxfb_delete_i2c_busses(struct tdfx_par *par) +{ + if (par->chan[0].par) + i2c_del_adapter(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_del_adapter(&par->chan[1].adapter); + par->chan[1].par = NULL; +} + +static int tdfxfb_probe_i2c_connector(struct tdfx_par *par, + struct fb_monspecs *specs) +{ + u8 *edid = NULL; + + DPRINTK("Probe DDC Bus\n"); + if (par->chan[0].par) + edid = fb_ddc_read(&par->chan[0].adapter); + + if (edid) { + fb_edid_to_monspecs(edid, specs); + kfree(edid); + return 0; + } + return 1; +} +#endif /* CONFIG_FB_3DFX_I2C */ + /** * tdfxfb_probe - Device Initializiation * @@ -1182,6 +1395,8 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, struct tdfx_par *default_par; struct fb_info *info; int err, lpitch; + struct fb_monspecs *specs; + bool found; err = pci_enable_device(pdev); if (err) { @@ -1284,13 +1499,49 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, if (hwcursor) info->fix.smem_len = (info->fix.smem_len - 1024) & (PAGE_MASK << 1); - - if (!mode_option) + specs = &info->monspecs; + found = false; + info->var.bits_per_pixel = 8; +#ifdef CONFIG_FB_3DFX_I2C + tdfxfb_create_i2c_busses(info); + err = tdfxfb_probe_i2c_connector(default_par, specs); + + if (!err) { + if (specs->modedb == NULL) + DPRINTK("Unable to get Mode Database\n"); + else { + const struct fb_videomode *m; + + fb_videomode_to_modelist(specs->modedb, + specs->modedb_len, + &info->modelist); + m = fb_find_best_display(specs, &info->modelist); + if (m) { + fb_videomode_to_var(&info->var, m); + /* fill all other info->var's fields */ + if (tdfxfb_check_var(&info->var, info) < 0) + info->var = tdfx_var; + else + found = true; + } + } + } +#endif + if (!mode_option && !found) mode_option = "640x480@60"; - err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); - if (!err || err == 4) - info->var = tdfx_var; + if (mode_option) { + err = fb_find_mode(&info->var, info, mode_option, + specs->modedb, specs->modedb_len, + NULL, info->var.bits_per_pixel); + if (!err || err == 4) + info->var = tdfx_var; + } + + if (found) { + fb_destroy_modedb(specs->modedb); + specs->modedb = NULL; + } /* maximize virtual vertical length */ lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); @@ -1315,6 +1566,9 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, return 0; out_err_iobase: +#ifdef CONFIG_FB_3DFX_I2C + tdfxfb_delete_i2c_busses(default_par); +#endif if (default_par->mtrr_handle >= 0) mtrr_del(default_par->mtrr_handle, info->fix.smem_start, info->fix.smem_len); @@ -1379,6 +1633,9 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev) struct tdfx_par *par = info->par; unregister_framebuffer(info); +#ifdef CONFIG_FB_3DFX_I2C + tdfxfb_delete_i2c_busses(par); +#endif if (par->mtrr_handle >= 0) mtrr_del(par->mtrr_handle, info->fix.smem_start, info->fix.smem_len); @@ -1393,6 +1650,7 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev) release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); pci_set_drvdata(pdev, NULL); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 680642c089c9..a86046ff60ad 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -1663,7 +1663,7 @@ tgafb_register(struct device *dev) if (register_framebuffer(info) < 0) { printk(KERN_ERR "tgafb: Could not register framebuffer\n"); ret = -EINVAL; - goto err1; + goto err2; } if (tga_bus_pci) { @@ -1682,6 +1682,8 @@ tgafb_register(struct device *dev) return 0; + err2: + fb_dealloc_cmap(&info->cmap); err1: if (mem_base) iounmap(mem_base); diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 479b2e79ad68..03a9c35e9f55 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -2,7 +2,7 @@ * Frame buffer driver for Trident TGUI, Blade and Image series * * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> - * + * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl> * * CREDITS:(in order of appearance) * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video @@ -490,7 +490,6 @@ static void tgui_copy_rect(struct tridentfb_par *par, /* * Accel functions called by the upper layers */ -#ifdef CONFIG_FB_TRIDENT_ACCEL static void tridentfb_fillrect(struct fb_info *info, const struct fb_fillrect *fr) { @@ -565,11 +564,6 @@ static int tridentfb_sync(struct fb_info *info) par->wait_engine(par); return 0; } -#else -#define tridentfb_fillrect cfb_fillrect -#define tridentfb_copyarea cfb_copyarea -#define tridentfb_imageblit cfb_imageblit -#endif /* CONFIG_FB_TRIDENT_ACCEL */ /* * Hardware access functions @@ -1333,9 +1327,7 @@ static struct fb_ops tridentfb_ops = { .fb_fillrect = tridentfb_fillrect, .fb_copyarea = tridentfb_copyarea, .fb_imageblit = tridentfb_imageblit, -#ifdef CONFIG_FB_TRIDENT_ACCEL .fb_sync = tridentfb_sync, -#endif }; static int __devinit trident_pci_probe(struct pci_dev *dev, @@ -1359,10 +1351,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, chip_id = id->device; -#ifndef CONFIG_FB_TRIDENT_ACCEL - noaccel = 1; -#endif - /* If PCI id is 0x9660 then further detect chip type */ if (chip_id == TGUI9660) { @@ -1490,6 +1478,9 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, } else info->flags |= FBINFO_HWACCEL_DISABLED; + if (is_blade(chip_id) && chip_id != BLADE3D) + info->flags |= FBINFO_READS_FAST; + info->pixmap.addr = kmalloc(4096, GFP_KERNEL); if (!info->pixmap.addr) { err = -ENOMEM; @@ -1563,6 +1554,7 @@ static void __devexit trident_pci_remove(struct pci_dev *dev) release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); pci_set_drvdata(dev, NULL); kfree(info->pixmap.addr); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } @@ -1663,4 +1655,5 @@ module_exit(tridentfb_exit); MODULE_AUTHOR("Jani Monoses <jani@iv.ro>"); MODULE_DESCRIPTION("Framebuffer driver for Trident cards"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("cyblafb"); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 74ae75899009..0b370aebdbfd 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -189,7 +189,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task) uvfb_tasks[seq] = task; mutex_unlock(&uvfb_lock); - err = cn_netlink_send(m, 0, gfp_any()); + err = cn_netlink_send(m, 0, GFP_KERNEL); if (err == -ESRCH) { /* * Try to start the userspace helper if sending @@ -850,14 +850,16 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) if (vbemode) { for (i = 0; i < par->vbe_modes_cnt; i++) { if (par->vbe_modes[i].mode_id == vbemode) { + modeid = i; + uvesafb_setup_var(&info->var, info, + &par->vbe_modes[modeid]); fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, - &info->var, info); + &info->var, info); /* * With pixclock set to 0, the default BIOS * timings will be used in set_par(). */ info->var.pixclock = 0; - modeid = i; goto gotmode; } } @@ -904,8 +906,11 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) fb_videomode_to_var(&info->var, mode); } else { modeid = par->vbe_modes[0].mode_id; + uvesafb_setup_var(&info->var, info, + &par->vbe_modes[modeid]); fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, - &info->var, info); + &info->var, info); + goto gotmode; } } @@ -917,9 +922,9 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) if (modeid == -1) return -EINVAL; -gotmode: uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]); +gotmode: /* * If we are not VBE3.0+ compliant, we're done -- the BIOS will * ignore our timings anyway. @@ -1552,7 +1557,7 @@ static void __devinit uvesafb_init_info(struct fb_info *info, } info->flags = FBINFO_FLAG_DEFAULT | - (par->ypan) ? FBINFO_HWACCEL_YPAN : 0; + (par->ypan ? FBINFO_HWACCEL_YPAN : 0); if (!par->ypan) info->fbops->fb_pan_display = NULL; diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 7b0cef9ca8f9..4bb9a0b18950 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -119,7 +119,7 @@ static void set_valkyrie_clock(unsigned char *params); static int valkyrie_var_to_par(struct fb_var_screeninfo *var, struct fb_par_valkyrie *par, const struct fb_info *fb_info); -static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p); +static int valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p); static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix); static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p); @@ -381,18 +381,22 @@ int __init valkyriefb_init(void) valkyrie_choose_mode(p); mac_vmode_to_var(default_vmode, default_cmode, &p->info.var); - valkyrie_init_info(&p->info, p); + err = valkyrie_init_info(&p->info, p); + if (err < 0) + goto out_free; valkyrie_init_fix(&p->info.fix, p); if (valkyriefb_set_par(&p->info)) /* "can't happen" */ printk(KERN_ERR "valkyriefb: can't set default video mode\n"); if ((err = register_framebuffer(&p->info)) != 0) - goto out_free; + goto out_cmap_free; printk(KERN_INFO "fb%d: valkyrie frame buffer device\n", p->info.node); return 0; + out_cmap_free: + fb_dealloc_cmap(&p->info.cmap); out_free: if (p->frame_buffer) iounmap(p->frame_buffer); @@ -538,14 +542,15 @@ static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, /* ywrapstep, xpanstep, ypanstep */ } -static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p) +static int __init valkyrie_init_info(struct fb_info *info, + struct fb_info_valkyrie *p) { info->fbops = &valkyriefb_ops; info->screen_base = p->frame_buffer + 0x1000; info->flags = FBINFO_DEFAULT; info->pseudo_palette = p->pseudo_palette; - fb_alloc_cmap(&info->cmap, 256, 0); info->par = &p->par; + return fb_alloc_cmap(&info->cmap, 256, 0); } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index e16322d157d0..d6856f43d241 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -438,7 +438,7 @@ static int __init vesafb_probe(struct platform_device *dev) info->var = vesafb_defined; info->fix = vesafb_fix; info->flags = FBINFO_FLAG_DEFAULT | - (ypan) ? FBINFO_HWACCEL_YPAN : 0; + (ypan ? FBINFO_HWACCEL_YPAN : 0); if (!ypan) info->fbops->fb_pan_display = NULL; diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 93fe08d6c78f..cc919ae46571 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -543,6 +543,7 @@ static int vfb_remove(struct platform_device *dev) if (info) { unregister_framebuffer(info); rvfree(videomemory, videomemorysize); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } return 0; diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 632523ff1fb7..45c54bfe99bb 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -267,13 +267,17 @@ int viafb_wait_engine_idle(void) int loop = 0; while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) & - VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP)) + VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { + loop++; cpu_relax(); + } while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && - (loop++ < MAXLOOP)) + (loop < MAXLOOP)) { + loop++; cpu_relax(); + } return loop >= MAXLOOP; } diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 37b433a08ce8..e327b84820d2 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -2059,25 +2059,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry) if (viafb_entry) { entry = create_proc_entry("dvp0", 0, *viafb_entry); if (entry) { - entry->owner = THIS_MODULE; entry->read_proc = viafb_dvp0_proc_read; entry->write_proc = viafb_dvp0_proc_write; } entry = create_proc_entry("dvp1", 0, *viafb_entry); if (entry) { - entry->owner = THIS_MODULE; entry->read_proc = viafb_dvp1_proc_read; entry->write_proc = viafb_dvp1_proc_write; } entry = create_proc_entry("dfph", 0, *viafb_entry); if (entry) { - entry->owner = THIS_MODULE; entry->read_proc = viafb_dfph_proc_read; entry->write_proc = viafb_dfph_proc_write; } entry = create_proc_entry("dfpl", 0, *viafb_entry); if (entry) { - entry->owner = THIS_MODULE; entry->read_proc = viafb_dfpl_proc_read; entry->write_proc = viafb_dfpl_proc_write; } @@ -2086,7 +2082,6 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry) viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { entry = create_proc_entry("vt1636", 0, *viafb_entry); if (entry) { - entry->owner = THIS_MODULE; entry->read_proc = viafb_vt1636_proc_read; entry->write_proc = viafb_vt1636_proc_write; } |