diff options
| author | James Simmons <jsimmons@maxwell.earthlink.net> | 2002-12-31 01:59:18 -0800 |
|---|---|---|
| committer | James Simmons <jsimmons@maxwell.earthlink.net> | 2002-12-31 01:59:18 -0800 |
| commit | 0d80a81821bd4f7eb554135dec3f400519525af8 (patch) | |
| tree | 75f6a0b833400fe039db0e3d85fba360eedfb0e7 /drivers | |
| parent | 572f2a49e4297c946a77721b72db960984b78a6d (diff) | |
| parent | 9f880dd8ed32ee57c3489409e321675fde1544cf (diff) | |
Synced to Linus tree,
Diffstat (limited to 'drivers')
58 files changed, 7915 insertions, 3801 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 0920a11c3683..828df90fb64b 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -130,7 +130,7 @@ extern void console_map_init(void); extern void prom_con_init(void); #endif #ifdef CONFIG_MDA_CONSOLE -extern void mda_console_init(void); +extern int mda_console_init(void); #endif #ifdef CONFIG_FRAMEBUFFER_CONSOLE extern int fb_console_init(void); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e0f0af3145ba..254ad4f26c0d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -295,27 +295,21 @@ config FB_VGA16 vga16fb.o. config FB_STI - bool "Generic STI frame buffer device support" + bool "HP STI frame buffer device support" depends on FB && PARISC + default y ---help--- STI refers to the HP "Standard Text Interface" which is a set of BIOS routines contained in a ROM chip in HP PA-RISC based machines. - Enabling this option will implement the linux framebuffer device and - an fbcon color text console using calls to the STI BIOS routines. - The HP framebuffer device is usually planar, uses a strange memory - layout, and changing the plane mask to create colored pixels - requires a call to the STI routines, so do not expect /dev/fb to - actually be useful. However, it is the best we have as far as - graphics on the HP chipsets due to lack of hardware level - documentation for the various on-board HP chipsets used in these - systems. It is sufficient for basic text console functions, - including fonts. - - You should probably enable this option, unless you are having - trouble getting video when booting the kernel (make sure it isn't - just that you are running the console on the serial port, though). - Really old HP boxes may not have STI, and must use the PDC BIOS - console or the IODC BIOS. + Enabling this option will implement the linux framebuffer device + using calls to the STI BIOS routines for initialisation. + + If you enable this option, you will get a planar framebuffer device + /dev/fb which will work on the most common HP graphic cards of the + NGLE family, including the artist chips (in the 7xx and Bxxx series), + HCRX, HCRX24, CRX, CRX24 and VisEG series. + + It is safe to enable this option, so you should probably say "Y". config FB_MAC bool "Generic Macintosh display support" @@ -471,6 +465,44 @@ config FB_RIVA module will be called rivafb.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. +config FB_I810 + tristate "Intel 810/815 support (EXPERIMENTAL)" + depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI + help + This driver supports the on-board graphics built in to the Intel 810 + and 815 chipsets. Say Y if you have and plan to use such a board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called i810fb.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + For more information, please read + <file:Documentation/fb/intel810.txt> + +config FB_I810_GTF + bool "use VESA Generalized Timing Formula" + depends on FB_I810 + help + If you say Y, then the VESA standard, Generalized Timing Formula + or GTF, will be used to calculate the required video timing values + per video mode. Since the GTF allows nondiscrete timings + (nondiscrete being a range of values as opposed to discrete being a + set of values), you'll be able to use any combination of horizontal + and vertical resolutions, and vertical refresh rates without having + to specify your own timing parameters. This is especially useful + to maximize the performance of an aging display, or if you just + have a display with nonstandard dimensions. A VESA compliant + monitor is recommended, but can still work with non-compliant ones. + If you need or want this, then select this option. The timings may + not be compliant with Intel's recommended values. Use at your own + risk. + + If you say N, the driver will revert to discrete video timings + using a set recommended by Intel in their documentation. + + If unsure, say N. + config FB_MATROX tristate "Matrox acceleration" depends on FB && PCI @@ -759,7 +791,7 @@ config FB_TRIDENT The driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The - module will be called rivafb.o. If you want to compile it as a + module will be called tridentfb.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. config FB_PM3 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 7faee8111c81..c147b6de431e 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -12,8 +12,7 @@ export-objs := fbmem.o fbcmap.o fbmon.o modedb.o softcursor.o cfbfillrect.o obj-$(CONFIG_VT) += console/ -# Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x -obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o softcursor.o +obj-$(CONFIG_FB) += fbmem.o fbmon.o fbcmap.o modedb.o softcursor.o # Only include macmodes.o if we have FB support and are PPC ifeq ($(CONFIG_FB),y) obj-$(CONFIG_PPC) += macmodes.o @@ -27,13 +26,13 @@ obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_ATARI) += atafb.o obj-$(CONFIG_FB_ATY128) += aty128fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_RADEON) += radeonfb.o +obj-$(CONFIG_FB_RADEON) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblit.o +obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o -obj-$(CONFIG_FB_CT65550) += chipsfb.o +obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CYBER) += cyberfb.o @@ -42,7 +41,7 @@ obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbim obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o -obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblit.o cfbcopyarea.o +obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_CLGEN) += clgenfb.o @@ -63,7 +62,7 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o -obj-$(CONFIG_FB_STI) += stifb.o console/sticore.o +obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o @@ -74,6 +73,8 @@ obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o \ cfbimgblt.o vgastate.o obj-$(CONFIG_FB_SIS) += sis/ obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o +obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \ + cfbimgblt.o vgastate.o obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o @@ -82,7 +83,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_E1355) += epson1355fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o -obj-$(CONFIG_FB_VOODOO1) += sstfb.o +obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o # Files generated that shall be removed upon make clean clean-files := promcon_tbl.c diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 2f2154c677b2..cc51b69b25d2 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -70,7 +70,7 @@ #ifdef __powerpc__ #include <asm/prom.h> -#include <video/macmodes.h> +#include "../macmodes.h" #endif #ifdef __sparc__ #include <asm/pbm.h> @@ -84,9 +84,6 @@ #ifdef CONFIG_BOOTX_TEXT #include <asm/btext.h> #endif -#ifdef CONFIG_NVRAM -#include <linux/nvram.h> -#endif #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif @@ -226,14 +223,9 @@ static char *mode_option __initdata = NULL; #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED -static int default_vmode __initdata = VMODE_NVRAM; -static int default_cmode __initdata = CMODE_NVRAM; -#else static int default_vmode __initdata = VMODE_CHOOSE; static int default_cmode __initdata = CMODE_CHOOSE; #endif -#endif #ifdef CONFIG_ATARI static unsigned int mach64_count __initdata = 0; @@ -984,6 +976,7 @@ static int atyfb_release(struct fb_info *info, int user) var.yres_virtual = var.yres; } + fb_set_var(&var, -1, info); } } } @@ -1246,8 +1239,8 @@ static void atyfb_save_palette(struct atyfb_par *par, int enter) static void atyfb_palette(int enter) { - struct fb_info *info; struct atyfb_par *par; + struct fb_info *info; int i; for (i = 0; i < FB_MAX; i++) { @@ -1409,16 +1402,16 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par) static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when) { struct fb_info *info; - struct atyfb_par *par = (struct atyfb_par *) info->fb.par; + struct atyfb_par *par; int result; result = PBOOK_SLEEP_OK; for (info = first_display; info != NULL; info = par->next) { - struct fb_fix_screeninfo fix; int nb; - nb = fb_display[fg_console].var.yres * info->fix.line_length; + par = (struct atyfb_par *) info->fb.par; + nb = info->var.yres * info->fix.line_length; switch (when) { case PBOOK_SLEEP_REQUEST: @@ -1436,7 +1429,7 @@ static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when) if (par->blitter_may_be_busy) wait_for_idle(par); /* Stop accel engine (stop bus mastering) */ - if (par->accel_flags & FB_ACCELF_TEXT) + if (info->accel_flags & FB_ACCELF_TEXT) aty_reset_engine(par); /* Backup fb content */ @@ -1841,14 +1834,6 @@ static int __init aty_init(struct fb_info *info, const char *name) (&var, info, mode_option, 8)) var = default_var; } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) { - default_vmode = nvram_read_byte(NV_VMODE); - if (default_vmode <= 0 - || default_vmode > VMODE_MAX) - default_vmode = VMODE_CHOOSE; - } -#endif if (default_vmode == VMODE_CHOOSE) { if (M64_HAS(G3_PB_1024x768)) /* G3 PowerBook with 1024x768 LCD */ @@ -1870,10 +1855,6 @@ static int __init aty_init(struct fb_info *info, const char *name) if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; -#ifdef CONFIG_NVRAM - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); -#endif if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index 5545dbdb50ac..1179f00d6635 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -56,8 +56,6 @@ #include <asm/uaccess.h> #include <linux/fb.h> #include <linux/init.h> -#include <linux/selection.h> -#include <linux/console.h> #include <linux/pci.h> #include <linux/ioport.h> #include <asm/io.h> @@ -65,10 +63,7 @@ #ifdef CONFIG_ALL_PPC #include <asm/prom.h> #include <asm/pci-bridge.h> -#include <video/macmodes.h> -#ifdef CONFIG_NVRAM -#include <linux/nvram.h> -#endif +#include "macmodes.h" #endif #ifdef CONFIG_ADB_PMU @@ -285,7 +280,6 @@ struct aty128_constants { struct aty128_crtc { u32 gen_cntl; - u32 ext_cntl; u32 h_total, h_sync_strt_wid; u32 v_total, v_sync_strt_wid; u32 pitch; @@ -326,10 +320,13 @@ struct aty128fb_par { unsigned char *save_framebuffer; int pm_reg; int crt_on, lcd_on; + struct pci_dev *pdev; + struct fb_info *next; #endif - unsigned char red[64]; /* see comments in aty128fb_setcolreg */ - unsigned char green[64]; - unsigned char blue[64]; + u8 red[32]; /* see aty128fb_setcolreg */ + u8 green[64]; + u8 blue[32]; + u32 pseudo_palette[16]; /* used for TRUECOLOR */ }; #ifdef CONFIG_PMAC_PBOOK @@ -337,6 +334,7 @@ int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier aty128_sleep_notifier = { aty128_sleep_notify, SLEEP_LEVEL_VIDEO, }; +static struct fb_info *aty128_fb = NULL; #endif #define round_div(n, d) ((n+(d/2))/d) @@ -1203,7 +1201,11 @@ aty128fb_set_par(struct fb_info *info) { struct aty128fb_par *par = info->par; u32 config; - + int err; + + if ((err = aty128_decode_var(&info->var, par)) != 0) + return err; + if (par->blitter_may_be_busy) wait_for_idle(par); @@ -1271,15 +1273,22 @@ static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par) { int err; + struct aty128_crtc crtc; + struct aty128_pll pll; + struct aty128_ddafifo fifo_reg; - if ((err = aty128_var_to_crtc(var, &par->crtc, par))) + if ((err = aty128_var_to_crtc(var, &crtc, par))) return err; - if ((err = aty128_var_to_pll(var->pixclock, &par->pll, par))) + if ((err = aty128_var_to_pll(var->pixclock, &pll, par))) return err; - if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.depth, par))) + if ((err = aty128_ddafifo(&fifo_reg, &pll, crtc.depth, par))) return err; + + par->crtc = crtc; + par->pll = pll; + par->fifo_reg = fifo_reg; par->accel_flags = var->accel_flags; return 0; @@ -1312,12 +1321,13 @@ aty128_encode_var(struct fb_var_screeninfo *var, static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct aty128fb_par *par = info->par; + struct aty128fb_par par; int err; - if ((err = aty128_decode_var(var, par)) != 0) + par = *(struct aty128fb_par *)info->par; + if ((err = aty128_decode_var(var, &par)) != 0) return err; - aty128_encode_var(var, par); + aty128_encode_var(var, &par); return 0; } @@ -1602,7 +1612,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); - pmu_register_sleep_notifier(&aty128_sleep_notifier); + if (aty128_fb == NULL) { + /* XXX can only put one chip to sleep */ + aty128_fb = info; + } else + printk(KERN_WARNING "aty128fb: can only sleep one Rage 128\n"); + par->pdev = pdev; #endif printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", @@ -1647,8 +1662,7 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* We have the resources. Now virtualize them */ - size = sizeof(struct fb_info) + sizeof(struct aty128fb_par) + - sizeof(u32)*16; + size = sizeof(struct fb_info) + sizeof(struct aty128fb_par); if (!(info = kmalloc(size, GFP_ATOMIC))) { printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); goto err_unmap_out; @@ -1656,9 +1670,7 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) memset(info, 0, size); par = (struct aty128fb_par *)(info + 1); - info->pseudo_palette = (void *) (par + 1); - - memset(info, 0, sizeof(struct fb_info)); + info->pseudo_palette = par->pseudo_palette; info->par = par; info->fix = aty128fb_fix; @@ -1758,6 +1770,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev) pci_resource_len(pdev, 1)); release_mem_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); +#ifdef CONFIG_PMAC_PBOOK + if (info == aty128_fb) + aty128_fb = NULL; +#endif kfree(info); } #endif /* CONFIG_PCI */ @@ -2008,7 +2024,7 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, } } - if (par->crtc.depth == 16) { + if (par->crtc.depth == 16 && regno > 0) { /* * With the 5-6-5 split of bits for RGB at 16 bits/pixel, we * have 32 slots for R and B values but 64 slots for G values. @@ -2016,12 +2032,13 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * goes in a different slot, and we have to avoid disturbing * the other fields in the slots we touch. */ - par->red[regno] = red; par->green[regno] = green; - par->blue[regno] = blue; - if (regno > 0 && regno < 32) + if (regno < 32) { + par->red[regno] = red; + par->blue[regno] = blue; aty128_st_pal(regno * 8, red, par->green[regno*2], blue, par); + } red = par->red[regno/2]; blue = par->blue[regno/2]; regno <<= 2; @@ -2213,6 +2230,7 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend) { u32 pmgt; u16 pwr_command; + struct pci_dev *pdev = par->pdev; if (!par->pm_reg) return; @@ -2237,17 +2255,16 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend) aty_st_le32(BUS_CNTL1, 0x00000010); aty_st_le32(MEM_POWER_MISC, 0x0c830000); mdelay(100); - pci_read_config_word(par->pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); /* Switch PCI power management to D2 */ - pci_write_config_word(par->pdev, par->pm_reg+PCI_PM_CTRL, + pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); - pci_read_config_word(par->pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); } else { /* Switch back PCI power management to D0 */ mdelay(100); - pci_write_config_word(par->pdev, par->pm_reg+PCI_PM_CTRL, 0); - mdelay(100); - pci_read_config_word(par->pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, 0); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); mdelay(100); } } @@ -2259,10 +2276,13 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend) int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when) { - int result = PBOOK_SLEEP_OK, nb; - struct fb_info *info = info; /* FIXME!!! How do find which framebuffer */ - struct aty128fb_par *par = info->par; + int nb; + struct fb_info *info = aty128_fb; + struct aty128fb_par *par; + if (info == NULL) + return PBOOK_SLEEP_OK; + par = info->par; nb = info->var.yres * info->fix.line_length; switch (when) { @@ -2311,17 +2331,23 @@ aty128_sleep_notify(struct pmu_sleep_notifier *self, int when) aty128fb_blank(0, info); break; } - return result; + return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ int __init aty128fb_init(void) { +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&aty128_sleep_notifier); +#endif return pci_module_init(&aty128fb_driver); } static void __exit aty128fb_exit(void) { +#ifdef CONFIG_PMAC_PBOOK + pmu_unregister_sleep_notifier(&aty128_sleep_notifier); +#endif pci_unregister_driver(&aty128fb_driver); } diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index f99a1692d5cb..a009d737eac2 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -400,11 +400,6 @@ void cfb_copyarea(struct fb_info *p, struct fb_copyarea *area) } } -#ifdef MODULE -int init_module(void) { return 0; }; -void cleanup_module(void) {}; -#endif - EXPORT_SYMBOL(cfb_copyarea); MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index fd272386e6c3..9d4a5735522e 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -443,11 +443,6 @@ void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect) } } -#ifdef MODULE -int init_module(void) { return 0; }; -void cleanup_module(void) {}; -#endif - EXPORT_SYMBOL(cfb_fillrect); MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index f47b173b383e..5a343d0ae33f 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -21,13 +21,13 @@ * * FIXME * The code for 24 bit is horrible. It copies byte by byte size instead of - * words like the other sizes. Needs to be optimized. + * longs like the other sizes. Needs to be optimized. * * Tony: * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds * up the code significantly. * - * Code for depths not multiples of BITS_PER_WORD is still kludgy, which is + * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is * still processed a bit at a time. * * Also need to add code to deal with cards endians that are different than @@ -48,11 +48,7 @@ #define DPRINTK(fmt, args...) #endif -/* The following code can *not* handle a 64-bit long. */ -#define WORD u32 -#define BITS_PER_WORD 32 - -static WORD const cfb_tab8[] = { +static u32 cfb_tab8[] = { #if defined(__BIG_ENDIAN) 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, @@ -68,7 +64,7 @@ static WORD const cfb_tab8[] = { #endif }; -static WORD const cfb_tab16[] = { +static u32 cfb_tab16[] = { #if defined(__BIG_ENDIAN) 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff #elif defined(__LITTLE_ENDIAN) @@ -78,11 +74,11 @@ static WORD const cfb_tab16[] = { #endif }; -static WORD const cfb_tab32[] = { +static u32 cfb_tab32[] = { 0x00000000, 0xffffffff }; -#if BITS_PER_WORD == 32 +#if BITS_PER_LONG == 32 #define FB_WRITEL fb_writel #define FB_READL fb_readl #else @@ -91,7 +87,7 @@ static WORD const cfb_tab32[] = { #endif #if defined (__BIG_ENDIAN) -#define LEFT_POS(bpp) (BITS_PER_WORD - bpp) +#define LEFT_POS(bpp) (BITS_PER_LONG - bpp) #define NEXT_POS(pos, bpp) ((pos) -= (bpp)) #define SHIFT_HIGH(val, bits) ((val) >> (bits)) #define SHIFT_LOW(val, bits) ((val) << (bits)) @@ -103,25 +99,24 @@ static WORD const cfb_tab32[] = { #endif static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - WORD start_index, WORD pitch_index) + unsigned long start_index, unsigned long pitch_index) { /* Draw the penguin */ - int i, n; - WORD bitmask = SHIFT_LOW(~0UL, BITS_PER_WORD - p->var.bits_per_pixel); + unsigned long *dst, *dst2, color = 0, val, shift; + int i, n, bpp = p->var.bits_per_pixel; + unsigned long null_bits = BITS_PER_LONG - bpp; u32 *palette = (u32 *) p->pseudo_palette; - WORD *dst, *dst2, color = 0, val, shift; - WORD null_bits = BITS_PER_WORD - p->var.bits_per_pixel; u8 *src = image->data; - dst2 = (WORD *) dst1; + dst2 = (unsigned long *) dst1; for (i = image->height; i--; ) { n = image->width; - dst = (WORD *) dst1; + dst = (unsigned long *) dst1; shift = 0; val = 0; if (start_index) { - WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index)); + unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index)); val = FB_READL(dst) & start_mask; shift = start_index; @@ -129,23 +124,24 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 while (n--) { if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR ) - color = palette[*src] & bitmask; + color = palette[*src]; else - color = *src & bitmask; + color = *src; + color <<= LEFT_POS(bpp); val |= SHIFT_HIGH(color, shift); if (shift >= null_bits) { FB_WRITEL(val, dst++); if (shift == null_bits) val = 0; else - val = SHIFT_LOW(color, BITS_PER_WORD - shift); + val = SHIFT_LOW(color, BITS_PER_LONG - shift); } - shift += p->var.bits_per_pixel; - shift &= (BITS_PER_WORD - 1); + shift += bpp; + shift &= (BITS_PER_LONG - 1); src++; } if (shift) { - WORD end_mask = SHIFT_HIGH(~0UL, shift); + unsigned long end_mask = SHIFT_HIGH(~0UL, shift); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -153,35 +149,35 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 if (pitch_index) { dst2 += p->fix.line_length; dst1 = (char *) dst2; - (size_t) dst1 &= ~(sizeof(WORD) - 1); + (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1); start_index += pitch_index; - start_index &= BITS_PER_WORD - 1; + start_index &= BITS_PER_LONG - 1; } } } static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - WORD fgcolor, WORD bgcolor, - WORD start_index, WORD pitch_index) + unsigned long fgcolor, unsigned long bgcolor, + unsigned long start_index, unsigned long pitch_index) { - WORD i, j, l = 8; - WORD shift, color, bpp = p->var.bits_per_pixel; - WORD *dst, *dst2, val, pitch = p->fix.line_length; - WORD null_bits = BITS_PER_WORD - bpp; + unsigned long i, j, l = 8; + unsigned long shift, color, bpp = p->var.bits_per_pixel; + unsigned long *dst, *dst2, val, pitch = p->fix.line_length; + unsigned long null_bits = BITS_PER_LONG - bpp; u8 *src = image->data; - dst2 = (WORD *) dst1; + dst2 = (unsigned long *) dst1; for (i = image->height; i--; ) { shift = 0; val = 0; j = image->width; - dst = (WORD *) dst1; + dst = (unsigned long *) dst1; /* write leading bits */ if (start_index) { - WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index)); + unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index)); val = FB_READL(dst) & start_mask; shift = start_index; @@ -192,6 +188,7 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 color = fgcolor; else color = bgcolor; + color <<= LEFT_POS(bpp); val |= SHIFT_HIGH(color, shift); /* Did the bitshift spill bits to the next long? */ @@ -200,15 +197,15 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 if (shift == null_bits) val = 0; else - val = SHIFT_LOW(color, BITS_PER_WORD - shift); + val = SHIFT_LOW(color, BITS_PER_LONG - shift); } shift += bpp; - shift &= (BITS_PER_WORD - 1); + shift &= (BITS_PER_LONG - 1); if (!l) { l = 8; src++; }; } /* write trailing bits */ if (shift) { - WORD end_mask = SHIFT_HIGH(~0UL, shift); + unsigned long end_mask = SHIFT_HIGH(~0UL, shift); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -217,24 +214,24 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 if (pitch_index) { dst2 += pitch; dst1 = (char *) dst2; - (size_t) dst1 &= ~(sizeof(WORD) - 1); + (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1); start_index += pitch_index; - start_index &= BITS_PER_WORD - 1; + start_index &= BITS_PER_LONG - 1; } } } static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - WORD fgcolor, WORD bgcolor) + unsigned long fgcolor, unsigned long bgcolor) { int i, j, k, l = 8, n; - WORD bit_mask, end_mask, eorx; - WORD fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel; - WORD tmp = (1 << bpp) - 1; - WORD ppw = BITS_PER_WORD/bpp, ppos; - WORD *dst; + unsigned long bit_mask, end_mask, eorx; + unsigned long fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel; + unsigned long tmp = (1 << bpp) - 1; + unsigned long ppw = BITS_PER_LONG/bpp, ppos; + unsigned long *dst; u32 *tab = NULL; char *src = image->data; @@ -267,7 +264,7 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 k = image->width/ppw; for (i = image->height; i--; ) { - dst = (WORD *) dst1; + dst = (unsigned long *) dst1; for (j = k; j--; ) { l -= ppw; @@ -295,8 +292,8 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 void cfb_imageblit(struct fb_info *p, struct fb_image *image) { int x2, y2, vxres, vyres; - WORD fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; - WORD bpl = sizeof(WORD), bpp = p->var.bits_per_pixel; + unsigned long fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; + unsigned long bpl = sizeof(unsigned long), bpp = p->var.bits_per_pixel; u8 *dst1; vxres = p->var.xres_virtual; @@ -319,7 +316,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image) image->height = y2 - image->dy; bitstart = (image->dy * p->fix.line_length * 8) + (image->dx * bpp); - start_index = bitstart & (BITS_PER_WORD - 1); + start_index = bitstart & (BITS_PER_LONG - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; bitstart /= 8; @@ -336,7 +333,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image) bgcolor = image->bg_color; } - if (BITS_PER_WORD % bpp == 0 && !start_index && !pitch_index && + if (BITS_PER_LONG % bpp == 0 && !start_index && !pitch_index && bpp >= 8 && bpp <= 32 && (image->width & 7) == 0) fast_imageblit(image, p, dst1, fgcolor, bgcolor); else @@ -346,11 +343,6 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image) color_imageblit(image, p, dst1, start_index, pitch_index); } -#ifdef MODULE -int init_module(void) { return 0; }; -void cleanup_module(void) {}; -#endif - EXPORT_SYMBOL(cfb_imageblit); MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index ee43294488f1..cd8bb196e904 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -2,7 +2,7 @@ * drivers/video/chipsfb.c -- frame buffer device for * Chips & Technologies 65550 chip. * - * Copyright (C) 1998 Paul Mackerras + * Copyright (C) 1998-2002 Paul Mackerras * * This file is derived from the Powermac "chips" driver: * Copyright (C) 1997 Fabio Riccardi. @@ -26,7 +26,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/fb.h> -#include <linux/selection.h> #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> @@ -39,34 +38,11 @@ #include <linux/pmu.h> #endif -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/macmodes.h> - -struct fb_info_chips { - struct fb_info info; - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; - struct display disp; - struct { - __u8 red, green, blue; - } palette[256]; - struct pci_dev *pdev; - unsigned long frame_buffer_phys; - __u8 *frame_buffer; - unsigned long blitter_regs_phys; - __u32 *blitter_regs; - unsigned long blitter_data_phys; - __u8 *blitter_data; - struct fb_info_chips *next; -#ifdef CONFIG_PMAC_PBOOK - unsigned char *save_framebuffer; -#endif -#ifdef FBCON_HAS_CFB16 - u16 fbcon_cfb16_cmap[16]; -#endif -}; +/* + * Since we access the display with inb/outb to fixed port numbers, + * we can only handle one 6555x chip. -- paulus + */ +static struct fb_info chipsfb_info; #define write_ind(num, val, ap, dp) do { \ outb((num), (ap)); outb((val), (dp)); \ @@ -98,9 +74,8 @@ struct fb_info_chips { inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ } while (0) -static struct fb_info_chips *all_chips; - #ifdef CONFIG_PMAC_PBOOK +static unsigned char *save_framebuffer; int chips_sleep_notify(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier chips_sleep_notifier = { chips_sleep_notify, SLEEP_LEVEL_VIDEO, @@ -112,58 +87,29 @@ static struct pmu_sleep_notifier chips_sleep_notifier = { */ int chips_init(void); -static void chips_pci_init(struct pci_dev *dp); -static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -static int chips_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int chips_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); +static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *); +static int chipsfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int chipsfb_set_par(struct fb_info *info); static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); static int chipsfb_blank(int blank, struct fb_info *info); static struct fb_ops chipsfb_ops = { - .owner = THIS_MODULE, - .fb_get_fix = chips_get_fix, - .fb_get_var = chips_get_var, - .fb_set_var = chips_set_var, - .fb_get_cmap = chips_get_cmap, - .fb_set_cmap = gen_set_cmap, - .fb_setcolreg = chipsfb_setcolreg, - .fb_blank = chipsfb_blank, + .owner = THIS_MODULE, + .fb_check_var = chipsfb_check_var, + .fb_set_par = chipsfb_set_par, + .fb_setcolreg = chipsfb_setcolreg, + .fb_blank = chipsfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, }; -static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, - u_int *blue, u_int *transp, struct fb_info *info); -static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp); - -static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) +static int chipsfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { - struct fb_info_chips *cp = (struct fb_info_chips *) info; - - *fix = cp->fix; - return 0; -} - -static int chips_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - struct fb_info_chips *cp = (struct fb_info_chips *) info; - - *var = cp->var; - return 0; -} - -static int chips_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - struct fb_info_chips *cp = (struct fb_info_chips *) info; - struct display *disp = (con >= 0)? &fb_display[con]: &cp->disp; - if (var->xres > 800 || var->yres > 600 || var->xres_virtual > 800 || var->yres_virtual > 600 || (var->bits_per_pixel != 8 && var->bits_per_pixel != 16) @@ -171,198 +117,76 @@ static int chips_set_var(struct fb_var_screeninfo *var, int con, || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && - var->bits_per_pixel != disp->var.bits_per_pixel) { - chips_set_bitdepth(cp, disp, con, var->bits_per_pixel); - } + var->xres = var->xres_virtual = 800; + var->yres = var->yres_virtual = 600; return 0; } -static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) +static int chipsfb_set_par(struct fb_info *info) { - if (con == info->currcon) /* current console? */ - return fb_get_cmap(cmap, kspc, chipsfb_getcolreg, info); - if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + if (info->var.bits_per_pixel == 16) { + write_cr(0x13, 200); // Set line length (doublewords) + write_xr(0x81, 0x14); // 15 bit (555) color mode + write_xr(0x82, 0x00); // Disable palettes + write_xr(0x20, 0x10); // 16 bit blitter mode + + info->fix.line_length = 800*2; + info->fix.visual = FB_VISUAL_TRUECOLOR; + + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 5; + + } else { + /* p->var.bits_per_pixel == 8 */ + write_cr(0x13, 100); // Set line length (doublewords) + write_xr(0x81, 0x12); // 8 bit color mode + write_xr(0x82, 0x08); // Graphics gamma enable + write_xr(0x20, 0x00); // 8 bit blitter mode + + info->fix.line_length = 800; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->var.red.offset = info->var.green.offset = + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + } return 0; } -static int chipsfbcon_switch(int con, struct fb_info *info) -{ - struct fb_info_chips *p = (struct fb_info_chips *) info; - int new_bpp, old_bpp; - - /* Do we have to save the colormap? */ - if (fb_display[info->currcon].cmap.len) - fb_get_cmap(&fb_display[info->currcon].cmap, 1, chipsfb_getcolreg, info); - - new_bpp = fb_display[con].var.bits_per_pixel; - old_bpp = fb_display[info->currcon].var.bits_per_pixel; - info->currcon = con; - - if (new_bpp != old_bpp) - chips_set_bitdepth(p, &fb_display[con], con, new_bpp); - - do_install_cmap(con, info); - return 0; -} - -static int chipsfb_updatevar(int con, struct fb_info *info) -{ - return 0; -} - static int chipsfb_blank(int blank, struct fb_info *info) { - struct fb_info_chips *p = (struct fb_info_chips *) info; - int i; - +#ifdef CONFIG_PMAC_BACKLIGHT // used to disable backlight only for blank > 1, but it seems // useful at blank = 1 too (saves battery, extends backlight life) - if (blank) { -#ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_enable(0); -#endif /* CONFIG_PMAC_BACKLIGHT */ - /* get the palette from the chip */ - for (i = 0; i < 256; ++i) { - outb(i, 0x3c7); - udelay(1); - p->palette[i].red = inb(0x3c9); - p->palette[i].green = inb(0x3c9); - p->palette[i].blue = inb(0x3c9); - } - for (i = 0; i < 256; ++i) { - outb(i, 0x3c8); - udelay(1); - outb(0, 0x3c9); - outb(0, 0x3c9); - outb(0, 0x3c9); - } - } else { -#ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_enable(1); + set_backlight_enable(!blank); #endif /* CONFIG_PMAC_BACKLIGHT */ - for (i = 0; i < 256; ++i) { - outb(i, 0x3c8); - udelay(1); - outb(p->palette[i].red, 0x3c9); - outb(p->palette[i].green, 0x3c9); - outb(p->palette[i].blue, 0x3c9); - } - } - return 0; -} - -static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, - u_int *blue, u_int *transp, struct fb_info *info) -{ - struct fb_info_chips *p = (struct fb_info_chips *) info; - if (regno > 255) - return 1; - *red = (p->palette[regno].red<<8) | p->palette[regno].red; - *green = (p->palette[regno].green<<8) | p->palette[regno].green; - *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; - *transp = 0; - return 0; + return 1; /* get fb_blank to set the colormap to all black */ } static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { - struct fb_info_chips *p = (struct fb_info_chips *) info; - if (regno > 255) return 1; red >>= 8; green >>= 8; blue >>= 8; - p->palette[regno].red = red; - p->palette[regno].green = green; - p->palette[regno].blue = blue; outb(regno, 0x3c8); udelay(1); outb(red, 0x3c9); outb(green, 0x3c9); outb(blue, 0x3c9); -#ifdef FBCON_HAS_CFB16 - if (regno < 16) - p->fbcon_cfb16_cmap[regno] = ((red & 0xf8) << 7) - | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3); -#endif - return 0; } -static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp) -{ - int err; - struct fb_fix_screeninfo* fix = &p->fix; - struct fb_var_screeninfo* var = &p->var; - - if (bpp == 16) { - if (con == p->info.currcon) { - write_cr(0x13, 200); // Set line length (doublewords) - write_xr(0x81, 0x14); // 15 bit (555) color mode - write_xr(0x82, 0x00); // Disable palettes - write_xr(0x20, 0x10); // 16 bit blitter mode - } - - fix->line_length = 800*2; - fix->visual = FB_VISUAL_TRUECOLOR; - - var->red.offset = 10; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = var->green.length = var->blue.length = 5; - -#ifdef FBCON_HAS_CFB16 - disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = p->fbcon_cfb16_cmap; -#else - disp->dispsw = &fbcon_dummy; -#endif - } else if (bpp == 8) { - if (con == p->info.currcon) { - write_cr(0x13, 100); // Set line length (doublewords) - write_xr(0x81, 0x12); // 8 bit color mode - write_xr(0x82, 0x08); // Graphics gamma enable - write_xr(0x20, 0x00); // 8 bit blitter mode - } - - fix->line_length = 800; - fix->visual = FB_VISUAL_PSEUDOCOLOR; - - var->red.offset = var->green.offset = var->blue.offset = 0; - var->red.length = var->green.length = var->blue.length = 8; - -#ifdef FBCON_HAS_CFB8 - disp->dispsw = &fbcon_cfb8; -#else - disp->dispsw = &fbcon_dummy; -#endif - } - - var->bits_per_pixel = bpp; - disp->line_length = p->fix.line_length; - disp->visual = fix->visual; - disp->var = *var; - - if (p->info.changevar) - (*p->info.changevar)(con); - - if ((err = fb_alloc_cmap(&disp->cmap, 0, 0))) - return; - do_install_cmap(con, (struct fb_info *)p); -} - struct chips_init_reg { unsigned char addr; unsigned char data; @@ -473,7 +297,7 @@ static struct chips_init_reg chips_init_xr[] = { { 0xa8, 0x00 } }; -static void __init chips_hw_init(struct fb_info_chips *p) +static void __init chips_hw_init(void) { int i; @@ -492,12 +316,12 @@ static void __init chips_hw_init(struct fb_info_chips *p) write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); } -static void __init init_chips(struct fb_info_chips *p) -{ - int i; - - strcpy(p->fix.id, "C&T 65550"); - p->fix.smem_start = p->frame_buffer_phys; +static struct fb_fix_screeninfo chipsfb_fix __initdata = { + .id = "C&T 65550", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, + .line_length = 800, // FIXME: Assumes 1MB frame buffer, but 65550 supports 1MB or 2MB. // * "3500" PowerBook G3 (the original PB G3) has 2MB. @@ -506,115 +330,75 @@ static void __init init_chips(struct fb_info_chips *p) // for a second pair of DRAMs. (Thanks, Apple!) // * 3400 has 1MB (I think). Don't know if it's expandable. // -- Tim Seufert - p->fix.smem_len = 0x100000; // 1MB - p->fix.type = FB_TYPE_PACKED_PIXELS; - p->fix.visual = FB_VISUAL_PSEUDOCOLOR; - p->fix.line_length = 800; - - p->var.xres = 800; - p->var.yres = 600; - p->var.xres_virtual = 800; - p->var.yres_virtual = 600; - p->var.bits_per_pixel = 8; - p->var.red.length = p->var.green.length = p->var.blue.length = 8; - p->var.height = p->var.width = -1; - p->var.vmode = FB_VMODE_NONINTERLACED; - p->var.pixclock = 10000; - p->var.left_margin = p->var.right_margin = 16; - p->var.upper_margin = p->var.lower_margin = 16; - p->var.hsync_len = p->var.vsync_len = 8; - - p->disp.var = p->var; - p->disp.cmap.red = NULL; - p->disp.cmap.green = NULL; - p->disp.cmap.blue = NULL; - p->disp.cmap.transp = NULL; - p->disp.visual = p->fix.visual; - p->disp.type = p->fix.type; - p->disp.type_aux = p->fix.type_aux; - p->disp.line_length = p->fix.line_length; - p->disp.can_soft_blank = 1; - p->disp.dispsw = &fbcon_cfb8; - p->disp.scrollmode = SCROLL_YREDRAW; - - strcpy(p->info.modename, p->fix.id); - p->info.node = NODEV; - p->info.fbops = &chipsfb_ops; - p->info.screen_base = p->frame_buffer; - p->info.disp = &p->disp; - p->info.currcon = -1; - p->info.fontname[0] = 0; - p->info.changevar = NULL; - p->info.switch_con = &chipsfbcon_switch; - p->info.updatevar = &chipsfb_updatevar; - p->info.flags = FBINFO_FLAG_DEFAULT; - - for (i = 0; i < 16; ++i) { - int j = color_table[i]; - p->palette[i].red = default_red[j]; - p->palette[i].green = default_grn[j]; - p->palette[i].blue = default_blu[j]; - } + .smem_len = 0x100000, /* 1MB */ +}; - if (register_framebuffer(&p->info) < 0) { - kfree(p); - return; - } +static struct fb_var_screeninfo chipsfb_var __initdata = { + .xres = 800, + .yres = 600, + .xres_virtual = 800, + .yres_virtual = 600, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, + .pixclock = 10000, + .left_margin = 16, + .right_margin = 16, + .upper_margin = 16, + .lower_margin = 16, + .hsync_len = 8, + .vsync_len = 8, +}; - printk("fb%d: Chips 65550 frame buffer (%dK RAM detected)\n", - minor(p->info.node), p->fix.smem_len / 1024); +static void __init init_chips(struct fb_info *p, unsigned long addr) +{ + p->fix = chipsfb_fix; + p->fix.smem_start = addr; - chips_hw_init(p); + p->var = chipsfb_var; -#ifdef CONFIG_PMAC_PBOOK - if (all_chips == NULL) - pmu_register_sleep_notifier(&chips_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ - p->next = all_chips; - all_chips = p; -} + p->node = NODEV; + p->fbops = &chipsfb_ops; + p->flags = FBINFO_FLAG_DEFAULT; -int __init chips_init(void) -{ - struct pci_dev *dp = NULL; + fb_alloc_cmap(&p->cmap, 256, 0); + + if (register_framebuffer(p) < 0) { + printk(KERN_ERR "C&T 65550 framebuffer failed to register\n"); + return; + } + + printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n", + minor(p->node), p->fix.smem_len / 1024); - while ((dp = pci_find_device(PCI_VENDOR_ID_CT, - PCI_DEVICE_ID_CT_65550, dp)) != NULL) - if ((dp->class >> 16) == PCI_BASE_CLASS_DISPLAY) - chips_pci_init(dp); - return all_chips? 0: -ENODEV; + chips_hw_init(); } -static void __init chips_pci_init(struct pci_dev *dp) +static int __devinit +chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { - struct fb_info_chips *p; + struct fb_info *p = &chipsfb_info; unsigned long addr, size; unsigned short cmd; if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) - return; - addr = dp->resource[0].start; - size = dp->resource[0].end + 1 - addr; + return -ENODEV; + addr = pci_resource_start(dp, 0); + size = pci_resource_len(dp, 0); if (addr == 0) - return; - p = kmalloc(sizeof(*p), GFP_ATOMIC); - if (p == 0) - return; - memset(p, 0, sizeof(*p)); - if (!request_mem_region(addr, size, "chipsfb")) { - kfree(p); - return; - } + return -ENODEV; + if (p->screen_base != 0) + return -EBUSY; + if (!request_mem_region(addr, size, "chipsfb")) + return -EBUSY; + #ifdef __BIG_ENDIAN addr += 0x800000; // Use big-endian aperture #endif - p->pdev = dp; - p->frame_buffer_phys = addr; - p->frame_buffer = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); - p->blitter_regs_phys = addr + 0x400000; - p->blitter_regs = ioremap(addr + 0x400000, 0x1000); - p->blitter_data_phys = addr + 0x410000; - p->blitter_data = ioremap(addr + 0x410000, 0x10000); /* we should use pci_enable_device here, but, the device doesn't declare its I/O ports in its BARs @@ -623,15 +407,68 @@ static void __init chips_pci_init(struct pci_dev *dp) cmd |= 3; /* enable memory and IO space */ pci_write_config_word(dp, PCI_COMMAND, cmd); - /* Clear the entire framebuffer */ - memset(p->frame_buffer, 0, 0x100000); - #ifdef CONFIG_PMAC_BACKLIGHT /* turn on the backlight */ set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ - init_chips(p); + p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); + if (p->screen_base == NULL) { + release_mem_region(addr, size); + return -ENOMEM; + } + + init_chips(p, addr); + +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&chips_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + /* Clear the entire framebuffer */ + memset(p->screen_base, 0, 0x100000); + + pci_set_drvdata(dp, p); + return 0; +} + +static void __devexit chipsfb_remove(struct pci_dev *dp) +{ + struct fb_info *p = pci_get_drvdata(dp); + + if (p != &chipsfb_info || p->screen_base == NULL) + return; + unregister_framebuffer(p); + iounmap(p->screen_base); + p->screen_base = NULL; + release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); + +#ifdef CONFIG_PMAC_PBOOK + pmu_unregister_sleep_notifier(&chips_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ +} + +static struct pci_device_id chipsfb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, chipsfb_pci_tbl); + +static struct pci_driver chipsfb_driver = { + .name = "chipsfb", + .id_table = chipsfb_pci_tbl, + .probe = chipsfb_pci_init, + .remove = __devexit_p(chipsfb_remove), +}; + +int __init chips_init(void) +{ + return pci_module_init(&chipsfb_driver); +} + +static void __exit chipsfb_exit(void) +{ + pci_unregister_driver(&chipsfb_driver); } #ifdef CONFIG_PMAC_PBOOK @@ -642,40 +479,37 @@ static void __init chips_pci_init(struct pci_dev *dp) int chips_sleep_notify(struct pmu_sleep_notifier *self, int when) { - struct fb_info_chips *p; - - for (p = all_chips; p != NULL; p = p->next) { - int nb = p->var.yres * p->fix.line_length; - - switch (when) { - case PBOOK_SLEEP_REQUEST: - p->save_framebuffer = vmalloc(nb); - if (p->save_framebuffer == NULL) - return PBOOK_SLEEP_REFUSE; - break; - case PBOOK_SLEEP_REJECT: - if (p->save_framebuffer) { - vfree(p->save_framebuffer); - p->save_framebuffer = 0; - } - break; - - case PBOOK_SLEEP_NOW: - chipsfb_blank(1, (struct fb_info *)p); - if (p->save_framebuffer) - memcpy(p->save_framebuffer, - p->frame_buffer, nb); - break; - case PBOOK_WAKE: - if (p->save_framebuffer) { - memcpy(p->frame_buffer, - p->save_framebuffer, nb); - vfree(p->save_framebuffer); - p->save_framebuffer = 0; - } - chipsfb_blank(0, (struct fb_info *)p); - break; + struct fb_info *p = &chipsfb_info; + int nb = p->var.yres * p->fix.line_length; + + if (p->screen_base == NULL) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + save_framebuffer = vmalloc(nb); + if (save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (save_framebuffer) { + vfree(save_framebuffer); + save_framebuffer = 0; + } + break; + case PBOOK_SLEEP_NOW: + chipsfb_blank(1, p); + if (save_framebuffer) + memcpy(save_framebuffer, p->screen_base, nb); + break; + case PBOOK_WAKE: + if (save_framebuffer) { + memcpy(p->screen_base, save_framebuffer, nb); + vfree(save_framebuffer); + save_framebuffer = 0; } + chipsfb_blank(0, p); + break; } return PBOOK_SLEEP_OK; } diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index bf88c5c88d8d..014a63c6ec45 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -66,13 +66,30 @@ config SGI_NEWPORT_CONSOLE # bool 'IODC console' CONFIG_IODC_CONSOLE config STI_CONSOLE - bool "STI console" + bool "STI text console" depends on PARISC + default y help The STI console is the builtin display/keyboard on HP-PARISC machines. Say Y here to build support for it into your kernel. The alternative is to use your primary serial port as a console. +config DUMMY_CONSOLE_COLUMNS + int "Initial number of STI console screen columns" if STI_CONSOLE + depends on STI_CONSOLE || FB_STI + default "160" + help + The default value is 160, which should fit a 1280x1024 monitor. + Select 80 if you use a 640x480 resolution by default. + +config DUMMY_CONSOLE_ROWS + int "Initial number of STI console screen rows" if STI_CONSOLE + depends on STI_CONSOLE || FB_STI + default "64" + help + The default value is 64, which should fit a 1280x1024 monitor. + Select 25 if you use a 640x480 resolution by default. + config PROM_CONSOLE bool "PROM console" depends on SPARC32 || SPARC64 @@ -120,19 +137,6 @@ config FBCON_ADVANCED If unsure, say N. # Guess what we need -config FBCON_STI - tristate - depends on !FBCON_ADVANCED && FRAMEBUFFER_CONSOLE && FB_STI - default y - -config FONTWIDTH8_ONLY - bool "Support only 8 pixels wide fonts" - depends on FRAMEBUFFER_CONSOLE - help - Answer Y here will make the kernel provide only the 8x8 fonts (these - are the less readable). - - If unsure, say N. config FONT_SUN8x16 bool "Sparc console 8x16 font" @@ -142,7 +146,7 @@ config FONT_SUN8x16 config FONT_SUN12x22 bool "Sparc console 12x22 font (not supported by all drivers)" - depends on FRAMEBUFFER_CONSOLE && !FONTWIDTH8_ONLY && (!SPARC32 && !SPARC64 && FONTS || SPARC32 || SPARC64) + depends on FRAMEBUFFER_CONSOLE && (!SPARC32 && !SPARC64 && FONTS || SPARC32 || SPARC64) help This is the high resolution console font for Sun machines with very big letters (like the letters used in the SPARC PROM). If the @@ -191,7 +195,7 @@ config FONT_8x16 config FONT_6x11 bool "Mac console 6x11 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE && !FONTWIDTH8_ONLY + depends on FRAMEBUFFER_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS && MAC help Small console font with Macintosh-style high-half glyphs. Some Mac diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 8c43a43cdf34..4d05b169ccbb 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -10,30 +10,16 @@ export-objs := fbcon.o fonts.o # Font handling font-objs := fonts.o -ifeq ($(CONFIG_FONT_SUN8x16),y) - font-objs += font_sun8x16.o -endif -ifeq ($(CONFIG_FONT_SUN12x22),y) - font-objs += font_sun12x22.o -endif -ifeq ($(CONFIG_FONT_8x8),y) - font-objs += font_8x8.o -endif -ifeq ($(CONFIG_FONT_8x16),y) - font-objs += font_8x16.o -endif -ifeq ($(CONFIG_FONT_6x11),y) - font-objs += font_6x11.o -endif -ifeq ($(CONFIG_FONT_PEARL_8x8),y) - font-objs += font_pearl_8x8.o -endif -ifeq ($(CONFIG_FONT_ACORN_8x8),y) - font-objs += font_acorn_8x8.o -endif -ifeq ($(CONFIG_FONT_MINI_4x6),y) - font-objs += font_mini_4x6.o -endif +font-objs-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o +font-objs-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o +font-objs-$(CONFIG_FONT_8x8) += font_8x8.o +font-objs-$(CONFIG_FONT_8x16) += font_8x16.o +font-objs-$(CONFIG_FONT_6x11) += font_6x11.o +font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o +font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o +font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o + +font-objs += $(font-objs-y) # Each configuration option enables a list of files. @@ -45,9 +31,7 @@ obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o -# Generic Low Level Drivers - -obj-$(CONFIG_FBCON_STI) += fbcon-sti.o +obj-$(CONFIG_FB_STI) += sticore.o # Files generated that shall be removed upon make clean clean-files := promcon_tbl.c diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index ba38857c8e3e..1fd54dc426d8 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -20,8 +20,10 @@ #define DUMMY_COLUMNS ORIG_VIDEO_COLS #define DUMMY_ROWS ORIG_VIDEO_LINES #elif defined(__hppa__) -#define DUMMY_COLUMNS 80 /* fixme ! (mine uses 160x64 at 1280x1024) */ -#define DUMMY_ROWS 25 +/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */ +#include <linux/config.h> +#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS +#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS #else #define DUMMY_COLUMNS 80 #define DUMMY_ROWS 25 diff --git a/drivers/video/console/fbcon-sti.c b/drivers/video/console/fbcon-sti.c deleted file mode 100644 index 35015f8c5592..000000000000 --- a/drivers/video/console/fbcon-sti.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * linux/drivers/video/fbcon-sti.c -- Low level frame buffer - * operations for generic HP video boards using STI (standard - * text interface) firmware - * - * Based on linux/drivers/video/fbcon-artist.c - * Created 5 Apr 1997 by Geert Uytterhoeven - * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. */ - -#include <linux/module.h> -#include <linux/tty.h> -#include <linux/console.h> -#include <linux/string.h> -#include <linux/fb.h> -#include <linux/delay.h> -#include <asm/gsc.h> /* for gsc_read/write */ -#include <asm/types.h> - -#include <video/fbcon.h> -#include <video/fbcon-mfb.h> - -#include "../sticore.h" - -static inline u32 -ram2log(void * addr) -{ - return (unsigned long) addr; -} - -/* All those functions need better names. */ - -static void -memcpy_fromhp_tohp(void *dest, void *src, int count) -{ - unsigned long d = ram2log(dest); - unsigned long s = ram2log(src); - - count += 3; - count &= ~3; /* XXX */ - - while(count) { - count --; - gsc_writel(~gsc_readl(s), d); - d += 32*4; - s += 32*4; - } -} - - -static void -memset_tohp(void *dest, u32 word, int count) -{ - unsigned long d = ram2log(dest); - - count += 3; - count &= ~3; - - while(count) { - count--; - gsc_writel(word, d); - d += 32; - } -} - -static u8 -readb_hp(void *src) -{ - unsigned long s = ram2log(src); - - return ~gsc_readb(s); -} - -static void -writeb_hp(u8 b, void *dst) -{ - unsigned long d = ram2log(dst); - - if((d&0xf0000000) != 0xf0000000) { - printk("writeb_hp %02x %p (%08lx) (%p)\n", - b, dst, d, __builtin_return_address(0)); - return; - } - - gsc_writeb(b, d); -} - -static void -fbcon_sti_setup(struct display *p) -{ - /* in kernel 2.5 the value of sadly line_length disapeared */ - if (p->var.xres_virtual /*line_length*/) - p->next_line = p->var.xres_virtual>>3; - else - p->next_line = 2048; /* default STI value */ - p->next_plane = 0; -} - -static void -fbcon_sti_bmove(struct display *p, int sy, int sx, - int dy, int dx, - int height, int width) -{ -#if 0 /* Unfortunately, still broken */ - sti_bmove(default_sti /* FIXME */, sy, sx, dy, dx, height, width); -#else - u8 *src, *dest; - u_int rows; - - if (sx == 0 && dx == 0 && width == p->next_line) { - src = p->fb_info->screen_base+sy*fontheight(p)*width; - dest = p->fb_info->screen_base+dy*fontheight(p)*width; - memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width); - } else if (dy <= sy) { - src = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx; - dest = p->fb_info->screen_base+dy*fontheight(p)*p->next_line+dx; - for (rows = height*fontheight(p); rows--;) { - memcpy_fromhp_tohp(dest, src, width); - src += p->next_line; - dest += p->next_line; - } - } else { - src = p->fb_info->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx; - dest = p->fb_info->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx; - for (rows = height*fontheight(p); rows--;) { - memcpy_fromhp_tohp(dest, src, width); - src -= p->next_line; - dest -= p->next_line; - } - } -#endif -} - -static void -fbcon_sti_clear(struct vc_data *conp, - struct display *p, int sy, int sx, - int height, int width) -{ - u8 *dest; - u_int rows; - int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; - - dest = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx; - - if (sx == 0 && width == p->next_line) { - if (inverse) - memset_tohp(dest, ~0, height*fontheight(p)*width); - else - memset_tohp(dest, 0, height*fontheight(p)*width); - } else - for (rows = height*fontheight(p); rows--; dest += p->next_line) - if (inverse) - memset_tohp(dest, 0xffffffff, width); - else - memset_tohp(dest, 0x00000000, width); -} - -static void fbcon_sti_putc(struct vc_data *conp, - struct display *p, int c, - int yy, int xx) -{ - u8 *dest, *cdat; - u_int rows, bold, revs, underl; - u8 d; - - dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx; - cdat = p->fontdata+(c&p->charmask)*fontheight(p); - bold = attr_bold(p,c); - revs = attr_reverse(p,c); - underl = attr_underline(p,c); - - for (rows = fontheight(p); rows--; dest += p->next_line) { - d = *cdat++; - if (underl && !rows) - d = 0xff; - else if (bold) - d |= d>>1; - if (revs) - d = ~d; - writeb_hp (d, dest); - } -} - -static void fbcon_sti_putcs(struct vc_data *conp, - struct display *p, - const unsigned short *s, - int count, int yy, int xx) -{ - u8 *dest, *dest0, *cdat; - u_int rows, bold, revs, underl; - u8 d; - u16 c; - - if(((unsigned)xx > 200) || ((unsigned) yy > 200)) { - printk("refusing to putcs %p %p %p %d %d %d (%p)\n", - conp, p, s, count, yy, xx, __builtin_return_address(0)); - return; - } - - - dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx; - if(((u32)dest0&0xf0000000)!=0xf0000000) { - printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n", - conp, p, s, count, yy, xx, __builtin_return_address(0), - dest0, p->fb_info->screen_base, yy, fontheight(p), p->next_line, - xx); - return; - } - - c = scr_readw(s); - bold = attr_bold(p, c); - revs = attr_reverse(p, c); - underl = attr_underline(p, c); - - while (count--) { - c = scr_readw(s++) & p->charmask; - dest = dest0++; - cdat = p->fontdata+c*fontheight(p); - for (rows = fontheight(p); rows--; dest += p->next_line) { - d = *cdat++; - if (0 && underl && !rows) - d = 0xff; - else if (0 && bold) - d |= d>>1; - if (revs) - d = ~d; - writeb_hp (d, dest); - } - } -} - -static void fbcon_sti_revc(struct display *p, - int xx, int yy) -{ - u8 *dest, d; - u_int rows; - - dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx; - for (rows = fontheight(p); rows--; dest += p->next_line) { - d = readb_hp(dest); - writeb_hp (~d, dest); - } -} - -static void -fbcon_sti_clear_margins(struct vc_data *conp, - struct display *p, - int bottom_only) -{ - u8 *dest; - int height, bottom; - int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; - - - /* XXX Need to handle right margin? */ - - height = p->var.yres - conp->vc_rows * fontheight(p); - if (!height) - return; - bottom = conp->vc_rows + p->yscroll; - if (bottom >= p->vrows) - bottom -= p->vrows; - dest = p->fb_info->screen_base + bottom * fontheight(p) * p->next_line; - if (inverse) - memset_tohp(dest, 0xffffffff, height * p->next_line); - else - memset_tohp(dest, 0x00000000, height * p->next_line); -} - - - /* - * `switch' for the low level operations - */ - -struct display_switch fbcon_sti = { - .setup = fbcon_sti_setup, - .bmove = fbcon_sti_bmove, - .clear = fbcon_sti_clear, - .putc = fbcon_sti_putc, - .putcs = fbcon_sti_putcs, - .revc = fbcon_sti_revc, - .clear_margins =fbcon_sti_clear_margins, - .fontwidthmask =FONTWIDTH(8) -}; - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 57cd3ca0a32d..a479845950cc 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -73,6 +73,7 @@ #include <linux/fb.h> #include <linux/vt_kern.h> #include <linux/selection.h> +#include <linux/font.h> #include <linux/smp.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -94,11 +95,8 @@ #include <asm/machdep.h> #include <asm/setup.h> #endif -#define INCLUDE_LINUX_LOGO_DATA -#include <asm/linux_logo.h> #include "fbcon.h" -#include "font.h" #ifdef FBCONDEBUG # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) @@ -204,8 +202,6 @@ static __inline__ void ypan_down(struct display *p, struct vc_data *vc, static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break); -static int fbcon_show_logo(void); - #ifdef CONFIG_MAC /* * On the Macintoy, there may or may not be a working VBL int. We need to probe @@ -292,7 +288,10 @@ void gen_set_disp(int con, struct fb_info *info) struct display *display = fb_display + con; display->can_soft_blank = info->fbops->fb_blank ? 1 : 0; - display->scrollmode = SCROLL_YNOMOVE; + if (info->var.accel_flags) + display->scrollmode = SCROLL_YNOMOVE; + else + display->scrollmode = SCROLL_YREDRAW; fbcon_changevar(con); return; } @@ -801,14 +800,6 @@ static int fbcon_changevar(int con) p->fontdata = font->data; } -#ifdef FONTWIDTH8_ONLY - if (!fontwidthvalid(p, vc->vc_font.width)) { - /* ++Geert: changed from panic() to `correct and continue' */ - printk(KERN_ERR - "fbcon_set_display: No support for fontwidth %d\n", - vc->vc_font.width); - } -#endif updatescrollmode(p, vc); old_cols = vc->vc_cols; @@ -927,11 +918,11 @@ static void fbcon_set_display(int con, int init, int logo) struct display *q = &fb_display[i]; struct vc_data *tmp = vc_cons[i].d; - if (fontwidthvalid(p, vc->vc_font.width)) { + if (!fontwidthvalid(p, vc->vc_font.width)) { /* If we are not the first console on this fb, copy the font from that console */ - tmp->vc_font.width = vc->vc_font.width; - tmp->vc_font.height = vc->vc_font.height; + vc->vc_font.width = tmp->vc_font.width; + vc->vc_font.height = tmp->vc_font.height; p->fontdata = q->fontdata; p->userfont = q->userfont; if (p->userfont) { @@ -951,14 +942,6 @@ static void fbcon_set_display(int con, int init, int logo) p->fontdata = font->data; } -#ifdef FONTWIDTH8_ONLY - if (!fontwidthvalid(p, vc->vc_font.width)) { - /* ++Geert: changed from panic() to `correct and continue' */ - printk(KERN_ERR - "fbcon_set_display: No support for fontwidth %d\n", - vc->vc_font.width); - } -#endif updatescrollmode(p, vc); old_cols = vc->vc_cols; @@ -1943,7 +1926,7 @@ static int fbcon_switch(struct vc_data *vc) accel_clear_margins(vc, p, 0); if (logo_shown == -2) { logo_shown = fg_console; - fbcon_show_logo(); /* This is protected above by initmem_freed */ + fb_show_logo(info); /* This is protected above by initmem_freed */ update_region(fg_console, vc->vc_origin + vc->vc_size_row * vc->vc_top, vc->vc_size_row * (vc->vc_bottom - @@ -2012,10 +1995,6 @@ static inline int fbcon_get_font(struct vc_data *vc, struct console_font_op *op) u8 *fontdata = p->fontdata; int i, j; -#ifdef CONFIG_FONTWIDTH8_ONLY - if (fontwidth(p) != 8) - return -EINVAL; -#endif op->width = vc->vc_font.width; op->height = vc->vc_font.height; op->charcount = (p->charmask == 0x1ff) ? 512 : 256; @@ -2030,9 +2009,7 @@ static inline int fbcon_get_font(struct vc_data *vc, struct console_font_op *op) data += 32; fontdata += j; } - } -#ifndef CONFIG_FONTWIDTH8_ONLY - else if (op->width <= 16) { + } else if (op->width <= 16) { j = vc->vc_font.height * 2; for (i = 0; i < op->charcount; i++) { memcpy(data, fontdata, j); @@ -2060,7 +2037,6 @@ static inline int fbcon_get_font(struct vc_data *vc, struct console_font_op *op) fontdata += j; } } -#endif return 0; } @@ -2213,10 +2189,6 @@ static inline int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) int i, k; u8 *new_data, *data = op->data, *p; -#ifdef CONFIG_FONTWIDTH8_ONLY - if (w != 8) - return -EINVAL; -#endif if ((w <= 0) || (w > 32) || (op->charcount != 256 && op->charcount != 512)) return -EINVAL; @@ -2244,9 +2216,7 @@ static inline int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) data += 32; p += h; } - } -#ifndef CONFIG_FONTWIDTH8_ONLY - else if (w <= 16) { + } else if (w <= 16) { h *= 2; for (i = 0; i < op->charcount; i++) { memcpy(p, data, h); @@ -2272,7 +2242,6 @@ static inline int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) p += h; } } -#endif /* we can do it in u32 chunks because of charcount is 256 or 512, so font length must be multiple of 256, at least. And 256 is multiple of 4 */ @@ -2345,8 +2314,7 @@ static struct fb_cmap palette_cmap = { static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) { - int unit = vc->vc_num; - struct display *p = &fb_display[unit]; + struct display *p = &fb_display[vc->vc_num]; struct fb_info *info = p->fb_info; int i, j, k; u8 val; @@ -2546,253 +2514,6 @@ static int fbcon_set_origin(struct vc_data *vc) return 0; } -static inline unsigned safe_shift(unsigned d, int n) -{ - return n < 0 ? d >> -n : d << n; -} - -static void __init fbcon_set_logocmap(struct fb_info *info) -{ - int i, j, n; - - for (i = 0; i < LINUX_LOGO_COLORS; i += n) { - n = LINUX_LOGO_COLORS - i; - if (n > 16) - /* palette_cmap provides space for only 16 colors at once */ - n = 16; - palette_cmap.start = 32 + i; - palette_cmap.len = n; - for (j = 0; j < n; ++j) { - palette_cmap.red[j] = - (linux_logo_red[i + j] << 8) | - linux_logo_red[i + j]; - palette_cmap.green[j] = - (linux_logo_green[i + j] << 8) | - linux_logo_green[i + j]; - palette_cmap.blue[j] = - (linux_logo_blue[i + j] << 8) | - linux_logo_blue[i + j]; - } - fb_set_cmap(&palette_cmap, 1, info); - } -} - -static void __init fbcon_set_logo_truepalette(struct fb_info *info, u32 *palette) -{ - unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; - unsigned char redmask, greenmask, bluemask; - int redshift, greenshift, blueshift; - int i; - - /* - * We have to create a temporary palette since console palette is only - * 16 colors long. - */ - /* Bug: Doesn't obey msb_right ... (who needs that?) */ - redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; - greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; - bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; - redshift = info->var.red.offset - (8 - info->var.red.length); - greenshift = info->var.green.offset - (8 - info->var.green.length); - blueshift = info->var.blue.offset - (8 - info->var.blue.length); - - - for ( i = 0; i < LINUX_LOGO_COLORS; i++) { - palette[i+32] = (safe_shift((linux_logo_red[i] & redmask), redshift) | - safe_shift((linux_logo_green[i] & greenmask), greenshift) | - safe_shift((linux_logo_blue[i] & bluemask), blueshift)); - } -} - -static void __init fbcon_set_logo_directpalette(struct fb_info *info, u32 *palette) -{ - int redshift, greenshift, blueshift; - int i; - - redshift = info->var.red.offset; - greenshift = info->var.green.offset; - blueshift = info->var.blue.offset; - - for (i = 32; i < LINUX_LOGO_COLORS; i++) - palette[i] = i << redshift | i << greenshift | i << blueshift; - -} - -static void __init fbcon_set_logo(struct fb_info *info, u8 *logo, int needs_logo) -{ - int i, j; - - switch (needs_logo) { - case 4: - for (i = 0; i < (LOGO_W * LOGO_H)/2; i++) { - logo[i*2] = linux_logo16[i] >> 4; - logo[(i*2)+1] = linux_logo16[i] & 0xf; - } - break; - case 1: - case ~1: - default: - for (i = 0; i < (LOGO_W * LOGO_H)/8; i++) - for (j = 0; j < 8; j++) - logo[i*2] = (linux_logo_bw[i] & (7 - j)) ? - ((needs_logo == 1) ? 1 : 0) : - ((needs_logo == 1) ? 0 : 1); - - break; - } -} - -/* - * Three (3) kinds of logo maps exist. linux_logo (>16 colors), linux_logo_16 - * (16 colors) and linux_logo_bw (2 colors). Depending on the visual format and - * color depth of the framebuffer, the DAC, the pseudo_palette, and the logo data - * will be adjusted accordingly. - * - * Case 1 - linux_logo: - * Color exceeds the number of console colors (16), thus we set the hardware DAC - * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. - * - * For visuals that require color info from the pseudo_palette, we also construct - * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags - * will be set. - * - * Case 2 - linux_logo_16: - * The number of colors just matches the console colors, thus there is no need - * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, - * each byte contains color information for two pixels (upper and lower nibble). - * To be consistent with fb_imageblit() usage, we therefore separate the two - * nibbles into separate bytes. The "needs_logo" flag will be set to 4. - * - * Case 3 - linux_logo_bw: - * This is similar with Case 2. Each byte contains information for 8 pixels. - * We isolate each bit and expand each into a byte. The "needs_logo" flag will - * be set to 1. - */ -static int __init fbcon_show_logo(void) - { - struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ - struct fb_info *info = p->fb_info; - struct vc_data *vc = info->display_fg; - struct fb_image image; - u32 *palette = NULL, *saved_palette = NULL; - unsigned char *fb = info->screen_base, *logo_new = NULL; - int done = 0, x; - int needs_cmapreset = 0; - int needs_truepalette = 0; - int needs_directpalette = 0; - int needs_logo = 0; - - /* Return if the frame buffer is not mapped */ - if (!fb || !info->fbops->fb_imageblit) - return 0; - - image.depth = info->var.bits_per_pixel; - - /* reasonable default */ - if (image.depth >= 8) - image.data = linux_logo; - else if (image.depth >= 4) - image.data = linux_logo16; - else - image.data = linux_logo_bw; - - switch (info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - needs_truepalette = 1; - if (image.depth >= 4 && image.depth <= 8) - needs_logo = 4; - else if (image.depth < 4) - needs_logo = 1; - break; - case FB_VISUAL_DIRECTCOLOR: - if (image.depth >= 24) { - needs_directpalette = 1; - needs_cmapreset = 1; - } - /* 16 colors */ - else if (image.depth >= 16) - needs_logo = 4; - /* 2 colors */ - else - needs_logo = 1; - break; - case FB_VISUAL_MONO01: - /* reversed 0 = fg, 1 = bg */ - needs_logo = ~1; - break; - case FB_VISUAL_MONO10: - needs_logo = 1; - break; - case FB_VISUAL_PSEUDOCOLOR: - default: - if (image.depth >= 8) - needs_cmapreset = 1; - /* fall through */ - case FB_VISUAL_STATIC_PSEUDOCOLOR: - /* 16 colors */ - if (image.depth >= 4 && image.depth < 8) - needs_logo = 4; - /* 2 colors */ - else if (image.depth < 4) - needs_logo = 1; - break; - } - - if (needs_cmapreset) - fbcon_set_logocmap(info); - - if (needs_truepalette || needs_directpalette) { - palette = kmalloc(256 * 4, GFP_KERNEL); - if (palette == NULL) - return 1; - - if (needs_truepalette) - fbcon_set_logo_truepalette(info, palette); - else - fbcon_set_logo_directpalette(info, palette); - - saved_palette = info->pseudo_palette; - info->pseudo_palette = palette; - } - - if (needs_logo) { - logo_new = kmalloc(LOGO_W * LOGO_H, GFP_KERNEL); - if (logo_new == NULL) { - if (palette) - kfree(palette); - if (saved_palette) - info->pseudo_palette = saved_palette; - return 1; - } - - image.data = logo_new; - fbcon_set_logo(info, logo_new, needs_logo); - } - - image.width = LOGO_W; - image.height = LOGO_H; - image.dy = 0; - - for (x = 0; x < num_online_cpus() * (LOGO_W + 8) && - x < info->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) { - image.dx = x; - info->fbops->fb_imageblit(info, &image); - done = 1; - } - - if (palette != NULL) - kfree(palette); - if (saved_palette != NULL) - info->pseudo_palette = saved_palette; - if (logo_new != NULL) - kfree(logo_new); - /* - * Modes not yet supported: packed pixels with depth != 8 (does such a - * thing exist in reality?) - */ - return done ? (LOGO_H + vc->vc_font.height - 1) / vc->vc_font.height : 0; -} - /* * The console `switch' structure for the frame buffer based console */ @@ -2823,7 +2544,6 @@ int __init fb_console_init(void) if (!num_registered_fb) return -ENODEV; take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); - __unsafe(THIS_MODULE); return 0; } diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index b49beeccc17e..23cc6c5c0504 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -51,28 +51,11 @@ extern struct display fb_display[MAX_NR_CONSOLES]; extern char con2fb_map[MAX_NR_CONSOLES]; extern void set_con2fb_map(int unit, int newidx); -#define fontheight(p) ((p)->_fontheight) - -#ifdef CONFIG_FONTWIDTH8_ONLY - -/* fontwidth w is supported by dispsw */ -#define FONTWIDTH(w) (1 << ((8) - 1)) -/* fontwidths w1-w2 inclusive are supported by dispsw */ -#define FONTWIDTHRANGE(w1,w2) FONTWIDTH(8) - -#define fontwidth(p) (8) - -#else - /* fontwidth w is supported by dispsw */ #define FONTWIDTH(w) (1 << ((w) - 1)) /* fontwidths w1-w2 inclusive are supported by dispsw */ #define FONTWIDTHRANGE(w1,w2) (FONTWIDTH(w2+1) - FONTWIDTH(w1)) -#define fontwidth(p) ((p)->_fontwidth) - -#endif - /* * Attribute Decoding */ diff --git a/drivers/video/console/font.h b/drivers/video/console/font.h deleted file mode 100644 index 16564d51d28e..000000000000 --- a/drivers/video/console/font.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * font.h -- `Soft' font definitions - * - * Created 1995 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#ifndef _VIDEO_CONSOLE_FONT_H -#define _VIDEO_CONSOLE_FONT_H - -#include <video/font.h> /* struct font_desc */ - -#define VGA8x8_IDX 0 -#define VGA8x16_IDX 1 -#define PEARL8x8_IDX 2 -#define VGA6x11_IDX 3 -#define SUN8x16_IDX 4 -#define SUN12x22_IDX 5 -#define ACORN8x8_IDX 6 -#define MINI4x6_IDX 7 - -extern struct font_desc font_vga_8x8, - font_vga_8x16, - font_pearl_8x8, - font_vga_6x11, - font_sun_8x16, - font_sun_12x22, - font_acorn_8x8, - font_mini_4x6; - -/* Find a font with a specific name */ - -extern struct font_desc *find_font(char *name); - -/* Get the default font for a specific screen size */ - -extern struct font_desc *get_default_font(int xres, int yres); - -/* Max. length for the name of a predefined font */ -#define MAX_FONT_NAME 32 - -#endif /* _VIDEO_CONSOLE_FONT_H */ diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c index 062f68d25734..32ff420cf840 100644 --- a/drivers/video/console/font_6x11.c +++ b/drivers/video/console/font_6x11.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX (11*256) diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c index a24ea2b6da52..e6f8dbaa122b 100644 --- a/drivers/video/console/font_8x16.c +++ b/drivers/video/console/font_8x16.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 4096 diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c index d7cfa088ef89..57fbe266a6b9 100644 --- a/drivers/video/console/font_8x8.c +++ b/drivers/video/console/font_8x8.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 2048 diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c index 3536c7edce1f..ed0ec4d1e3d7 100644 --- a/drivers/video/console/font_acorn_8x8.c +++ b/drivers/video/console/font_acorn_8x8.c @@ -1,8 +1,7 @@ /* Acorn-like font definition, with PC graphics characters */ #include <linux/config.h> - -#include "font.h" +#include <linux/font.h> static unsigned char acorndata_8x8[] = { /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index 8e4cb92c82b7..593b95500a0c 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -39,7 +39,7 @@ __END__; MSBit to LSBit = left to right. */ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 1536 diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c index c84048423cf8..5fa95f118818 100644 --- a/drivers/video/console/font_pearl_8x8.c +++ b/drivers/video/console/font_pearl_8x8.c @@ -9,7 +9,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 2048 diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c index 99f01c060fbb..05215d0c3e09 100644 --- a/drivers/video/console/font_sun12x22.c +++ b/drivers/video/console/font_sun12x22.c @@ -1,4 +1,4 @@ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 11264 diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index a8f6d60e8c6e..2af3ab354652 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c @@ -1,4 +1,4 @@ -#include "font.h" +#include <linux/font.h> #define FONTDATAMAX 4096 diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 9e88eeb9f479..d5605dc4f79f 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -74,7 +74,7 @@ static char *mda_type_name; /* console information */ -static int mda_first_vc = 13; +static int mda_first_vc = 1; static int mda_last_vc = 16; static struct vc_data *mda_display_fg = NULL; @@ -604,28 +604,22 @@ const struct consw mda_con = { .con_invert_region = mdacon_invert_region, }; -void __init mda_console_init(void) +int __init mda_console_init(void) { if (mda_first_vc > mda_last_vc) - return; + return 1; take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); -} - -#ifdef MODULE - -MODULE_LICENSE("GPL"); - -int init_module(void) -{ - mda_console_init(); - return 0; } -void cleanup_module(void) +void __exit mda_console_exit(void) { give_up_console(&mda_con); } -#endif +module_init(mda_console_init); +module_exit(mda_console_exit); + +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index fae9b93070ba..148c07239a9a 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -29,7 +29,7 @@ #define INCLUDE_LINUX_LOGO_DATA #include <asm/linux_logo.h> -#include "font.h" +#include <linux/font.h> #define LOGO_W 80 #define LOGO_H 80 diff --git a/drivers/video/console/sti.h b/drivers/video/console/sti.h deleted file mode 100644 index feea4fb92fbb..000000000000 --- a/drivers/video/console/sti.h +++ /dev/null @@ -1,289 +0,0 @@ -#define STI_REGION_MAX 8 -#define STI_DEV_NAME_LENGTH 32 - -struct sti_rom_font { - u16 first_char; - u16 last_char; - u8 width; - u8 height; - u8 font_type; - u8 bytes_per_char; - u32 next_font; - u8 underline_height; - u8 underline_pos; - u8 res008[2]; -}; - -struct sti_rom { - u8 type[4]; - u8 res004; - u8 num_mons; - u8 revno[2]; - u8 graphics_id[8]; - - u32 font_start; - u32 statesize; - u32 last_addr; - u32 region_list; - - u16 reentsize; - u16 maxtime; - u32 mon_tbl_addr; - u32 user_data_addr; - u32 sti_mem_req; - - u32 user_data_size; - u16 power; - u8 bus_support; - u8 ext_bus_support; - u8 alt_code_type; - u8 ext_dd_struct[3]; - u32 cfb_addr; - - u32 init_graph; - u32 state_mgmt; - u32 font_unpmv; - u32 block_move; - u32 self_test; - u32 excep_hdlr; - u32 inq_conf; - u32 set_cm_entry; - u32 dma_ctrl; - u8 res040[7 * 4]; - - u32 init_graph_m68k; - u32 flow_ctrl; - u32 user_timing; - u32 process_mgr; - u32 sti_util; - u32 end_addr; - u32 res0b8; - u32 res0bc; -}; - -struct sti_cooked_font { - struct sti_rom_font *raw; - struct sti_cooked_font *next_font; -}; - -struct sti_cooked_rom { - struct sti_rom *raw; - struct sti_cooked_font *font_start; - u32 *region_list; -}; - -struct sti_glob_cfg_ext { - u8 curr_mon; - u8 friendly_boot; - s16 power; - s32 freq_ref; - s32 *sti_mem_addr; - s32 *future_ptr; -}; - -struct sti_glob_cfg { - s32 text_planes; - s16 onscreen_x; - s16 onscreen_y; - s16 offscreen_x; - s16 offscreen_y; - s16 total_x; - s16 total_y; - u32 region_ptrs[STI_REGION_MAX]; - s32 reent_lvl; - s32 *save_addr; - struct sti_glob_cfg_ext *ext_ptr; -}; - -struct sti_init_flags { - u32 wait : 1; - u32 reset : 1; - u32 text : 1; - u32 nontext : 1; - u32 clear : 1; - u32 cmap_blk : 1; - u32 enable_be_timer : 1; - u32 enable_be_int : 1; - u32 no_chg_tx : 1; - u32 no_chg_ntx : 1; - u32 no_chg_bet : 1; - u32 no_chg_bei : 1; - u32 init_cmap_tx : 1; - u32 cmt_chg : 1; - u32 retain_ie : 1; - u32 pad : 17; - - s32 *future_ptr; -}; - -struct sti_init_inptr_ext { - u8 config_mon_type; - u8 pad[1]; - u16 inflight_data; - s32 *future_ptr; -}; - -struct sti_init_inptr { - s32 text_planes; - struct sti_init_inptr_ext *ext_ptr; -}; - -struct sti_init_outptr { - s32 errno; - s32 text_planes; - s32 *future_ptr; -}; - -struct sti_conf_flags { - u32 wait : 1; - u32 pad : 31; - s32 *future_ptr; -}; - -struct sti_conf_inptr { - s32 *future_ptr; -}; - -struct sti_conf_outptr_ext { - u32 crt_config[3]; - u32 crt_hdw[3]; - s32 *future_ptr; -}; - -struct sti_conf_outptr { - s32 errno; - s16 onscreen_x; - s16 onscreen_y; - s16 offscreen_x; - s16 offscreen_y; - s16 total_x; - s16 total_y; - s32 bits_per_pixel; - s32 bits_used; - s32 planes; - u8 dev_name[STI_DEV_NAME_LENGTH]; - u32 attributes; - struct sti_conf_outptr_ext *ext_ptr; -}; - - -struct sti_font_inptr { - u32 font_start_addr; - s16 index; - u8 fg_color; - u8 bg_color; - s16 dest_x; - s16 dest_y; - s32 *future_ptr; -}; - -struct sti_font_flags { - u32 wait : 1; - u32 non_text : 1; - u32 pad : 30; - - s32 *future_ptr; -}; - -struct sti_font_outptr { - s32 errno; - s32 *future_ptr; -}; - -struct sti_blkmv_flags { - u32 wait : 1; - u32 color : 1; - u32 clear : 1; - u32 non_text : 1; - u32 pad : 28; - s32 *future_ptr; -}; - -struct sti_blkmv_inptr { - u8 fg_color; - u8 bg_color; - s16 src_x; - s16 src_y; - s16 dest_x; - s16 dest_y; - s16 width; - s16 height; - s32 *future_ptr; -}; - -struct sti_blkmv_outptr { - s32 errno; - s32 *future_ptr; -}; - -struct sti_struct { - spinlock_t lock; - - struct sti_cooked_rom *rom; - - unsigned long font_unpmv; - unsigned long block_move; - unsigned long init_graph; - unsigned long inq_conf; - - struct sti_glob_cfg *glob_cfg; - struct sti_rom_font *font; - - s32 text_planes; - - char **mon_strings; - u32 *regions; - u8 *pci_regions; -}; - -#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \ - ({ \ - real32_call( func, (unsigned long)STI_PTR(flags), \ - STI_PTR(inptr), STI_PTR(outptr), \ - glob_cfg); \ - }) - -/* The latency of the STI functions cannot really be reduced by setting - * this to 0; STI doesn't seem to be designed to allow calling a different - * function (or the same function with different arguments) after a - * function exited with 1 as return value. - * - * As all of the functions below could be called from interrupt context, - * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1) - * block. Really bad latency there. - * - * Probably the best solution to all this is have the generic code manage - * the screen buffer and a kernel thread to call STI occasionally. - * - * Luckily, the frame buffer guys have the same problem so we can just wait - * for them to fix it and steal their solution. prumpf - * - * Actually, another long-term viable solution is to completely do STI - * support in userspace - that way we avoid the potential license issues - * of using proprietary fonts, too. */ - -#define STI_WAIT 1 -#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p)) -#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) ) - -#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x) -#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y) -#define sti_font_x(sti) (PTR_STI(sti->font)->width) -#define sti_font_y(sti) (PTR_STI(sti->font)->height) - -extern struct sti_struct * sti_init_roms(void); - -void sti_init_graph(struct sti_struct *sti); -void sti_inq_conf(struct sti_struct *sti); -void sti_putc(struct sti_struct *sti, int c, int y, int x); -void sti_set(struct sti_struct *sti, int src_y, int src_x, - int height, int width, u8 color); -void sti_clear(struct sti_struct *sti, int src_y, int src_x, - int height, int width); -void sti_bmove(struct sti_struct *sti, int src_y, int src_x, - int dst_y, int dst_x, int height, int width); - -/* XXX: this probably should not be here, but we rely on STI being - initialized early and independently of stifb at the moment, so - there's no other way for stifb to find it. */ -extern struct sti_struct default_sti; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 634b0289dea7..7294cfedcfac 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -1,7 +1,8 @@ /* - * linux/drivers/video/sticon.c - console driver using HP's STI firmware + * linux/drivers/video/console/sticon.c - console driver using HP's STI firmware * * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * Copyright (C) 2002 Helge Deller <deller@gmx.de> * * Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c, * which were @@ -31,18 +32,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. - */ -/* - * TODO: - * - call STI in virtual mode rather than in real mode - * - support for PCI-only STI ROMs (which don't have a traditional region - * list) - * - safe detection (i.e. verify there is a graphics device at a given - * address first, not just read a random device's io space) - * - support for multiple STI devices in one machine - * - support for byte-mode STI ROMs - * - support for just using STI to switch to a colour fb (stifb ?) - * - try to make it work on m68k hp workstations ;) + * */ #include <linux/init.h> @@ -51,92 +41,193 @@ #include <linux/console.h> #include <linux/errno.h> #include <linux/vt_kern.h> +#include <linux/kd.h> #include <linux/selection.h> #include <asm/io.h> -#include "sti.h" +#include "../sticore.h" + +/* switching to graphics mode */ +#define BLANK 0 +static int vga_is_gfx; + + +/* Software scrollback */ + +static unsigned long softback_buf, softback_curr; +static unsigned long softback_in; +static unsigned long /* softback_top, */ softback_end; +static int softback_lines; -/* STICON */ -static const char * __init -sticon_startup(void) +/* software cursor */ + +static int cursor_drawn; +#define CURSOR_DRAW_DELAY (1) +#define DEFAULT_CURSOR_BLINK_RATE (20) + +static int vbl_cursor_cnt; + +static inline void cursor_undrawn(void) { - return "STI console"; + vbl_cursor_cnt = 0; + cursor_drawn = 0; } -static int -sticon_set_palette(struct vc_data *c, unsigned char *table) + +static const char *__init sticon_startup(void) { - return -EINVAL; + return "STI console"; } -static int -sticon_font_op(struct vc_data *c, struct console_font_op *op) + +static int sticon_set_palette(struct vc_data *c, unsigned char *table) { - return -ENOSYS; + return -EINVAL; +} + +static int sticon_font_op(struct vc_data *c, struct console_font_op *op) +{ + return -ENOSYS; } static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) { - sti_putc(&default_sti, c, ypos, xpos); + int unit = conp->vc_num; + int redraw_cursor = 0; + + if (vga_is_gfx || console_blanked) + return; + + if (vt_cons[unit]->vc_mode != KD_TEXT) + return; +#if 0 + if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) { + cursor_undrawn(); + redraw_cursor = 1; + } +#endif + + sti_putc(default_sti, c, ypos, xpos); + + if (redraw_cursor) + vbl_cursor_cnt = CURSOR_DRAW_DELAY; } static void sticon_putcs(struct vc_data *conp, const unsigned short *s, - int count, int ypos, int xpos) + int count, int ypos, int xpos) { - while(count--) { - sti_putc(&default_sti, scr_readw(s++), ypos, xpos++); - } + int unit = conp->vc_num; + int redraw_cursor = 0; + + if (vga_is_gfx || console_blanked) + return; + + if (vt_cons[unit]->vc_mode != KD_TEXT) + return; + +#if 0 + if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) && + (p->cursor_x < (xpos + count))) { + cursor_undrawn(); + redraw_cursor = 1; + } +#endif + + while (count--) { + sti_putc(default_sti, scr_readw(s++), ypos, xpos++); + } + + if (redraw_cursor) + vbl_cursor_cnt = CURSOR_DRAW_DELAY; } static void sticon_cursor(struct vc_data *conp, int mode) { + unsigned short car1; + + car1 = conp->vc_screenbuf[conp->vc_x + conp->vc_y * conp->vc_cols]; + switch (mode) { + case CM_ERASE: + sti_putc(default_sti, car1, conp->vc_y, conp->vc_x); + break; + case CM_MOVE: + case CM_DRAW: + switch (conp->vc_cursor_type & 0x0f) { + case CUR_UNDERLINE: + case CUR_LOWER_THIRD: + case CUR_LOWER_HALF: + case CUR_TWO_THIRDS: + case CUR_BLOCK: + sti_putc(default_sti, (car1 & 255) + (0 << 8) + (7 << 11), + conp->vc_y, conp->vc_x); + break; + } + break; + } } -static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, - int count) +static int +sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) { - struct sti_struct *sti = &default_sti; - - if(console_blanked) - return 0; - - sticon_cursor(conp, CM_ERASE); + struct sti_struct *sti = default_sti; - switch(dir) { - case SM_UP: - sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols); - sti_clear(sti, b-count, 0, count, conp->vc_cols); + if (vga_is_gfx) + return 0; - break; + sticon_cursor(conp, CM_ERASE); - case SM_DOWN: - sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols); + switch (dir) { + case SM_UP: + sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); + break; - break; - } + case SM_DOWN: + sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); + break; + } - return 0; + return 0; } - -static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, - int height, int width) + +static void +sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) { - sti_bmove(&default_sti, sy, sx, dy, dx, height, width); + if (!width || !height) + return; +#if 0 + if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || + ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && + (dx <= p->cursor_x) && (p->cursor_x < dx+width))) + sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/); +#endif + + sti_bmove(default_sti, sy, sx, dy, dx, height, width); } static void sticon_init(struct vc_data *c, int init) { - struct sti_struct *sti = &default_sti; - int vc_cols, vc_rows; - - sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0); - c->vc_can_do_color = 1; - vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti); - vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti); - - vc_resize(c->vc_num, vc_cols, vc_rows); + struct sti_struct *sti = default_sti; + int vc_cols, vc_rows; + + sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0); + vc_cols = sti_onscreen_x(sti) / sti->font_width; + vc_rows = sti_onscreen_y(sti) / sti->font_height; + c->vc_can_do_color = 1; + + if (init) { + c->vc_cols = vc_cols; + c->vc_rows = vc_rows; + } else { + /* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */ + /* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */ + vc_resize(c->vc_num, vc_cols, vc_rows); +/* vc_resize_con(vc_rows, vc_cols, c->vc_num); */ + } } static void sticon_deinit(struct vc_data *c) @@ -144,71 +235,170 @@ static void sticon_deinit(struct vc_data *c) } static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, - int width) + int width) { - sti_clear(&default_sti, sy, sx, height, width); + if (!height || !width) + return; + + sti_clear(default_sti, sy, sx, height, width, conp->vc_video_erase_char); } static int sticon_switch(struct vc_data *conp) { - return 0; + return 1; /* needs refreshing */ } -static int sticon_blank(struct vc_data *conp, int blank) +static int sticon_set_origin(struct vc_data *conp) { - return 0; + return 0; +} + +static int sticon_blank(struct vc_data *c, int blank) +{ + switch (blank) { + case 0: /* unblank */ + vga_is_gfx = 0; + /* Tell console.c that it has to restore the screen itself */ + return 1; + case 1: /* normal blanking */ + default: /* VESA blanking */ + if (vga_is_gfx) + return 0; + sticon_set_origin(c); + sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK); + return 1; + case -1: /* Entering graphic mode */ + sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK); + vga_is_gfx = 1; + return 1; + } + return 1; /* console needs to restore screen itself */ } static int sticon_scrolldelta(struct vc_data *conp, int lines) { - return 0; + return 0; } -static int sticon_set_origin(struct vc_data *conp) +static u16 *sticon_screen_pos(struct vc_data *conp, int offset) { - return 0; + int line; + unsigned long p; + + if (conp->vc_num != fg_console || !softback_lines) + return (u16 *)(conp->vc_origin + offset); + line = offset / conp->vc_size_row; + if (line >= softback_lines) + return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row); + p = softback_curr + offset; + if (p >= softback_end) + p += softback_buf - softback_end; + return (u16 *)p; } -static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse) +static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, + int *px, int *py) { - u8 attr = ((color & 0x70) >> 1) | ((color & 7)); + int x, y; + unsigned long ret; + if (pos >= conp->vc_origin && pos < conp->vc_scr_end) { + unsigned long offset = (pos - conp->vc_origin) / 2; + + x = offset % conp->vc_cols; + y = offset / conp->vc_cols; + if (conp->vc_num == fg_console) + y += softback_lines; + ret = pos + (conp->vc_cols - x) * 2; + } else if (conp->vc_num == fg_console && softback_lines) { + unsigned long offset = pos - softback_curr; + + if (pos < softback_curr) + offset += softback_end - softback_buf; + offset /= 2; + x = offset % conp->vc_cols; + y = offset / conp->vc_cols; + ret = pos + (conp->vc_cols - x) * 2; + if (ret == softback_end) + ret = softback_buf; + if (ret == softback_in) + ret = conp->vc_origin; + } else { + /* Should not happen */ + x = y = 0; + ret = conp->vc_origin; + } + if (px) *px = x; + if (py) *py = y; + return ret; +} - if(reverse) { - color = ((color>>3)&0x7) | ((color &0x7)<<3); - } +static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, + u8 blink, u8 underline, u8 reverse) +{ + u8 attr = ((color & 0x70) >> 1) | ((color & 7)); + if (reverse) { + color = ((color >> 3) & 0x7) | ((color & 0x7) << 3); + } - return attr; + return attr; +} + +void sticon_invert_region(struct vc_data *conp, u16 *p, int count) +{ + int col = 1; /* vga_can_do_color; */ + + while (count--) { + u16 a = scr_readw(p); + + if (col) + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + else + a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700; + + scr_writew(a, p++); + } +} + +void sticon_save_screen(struct vc_data *conp) +{ } struct consw sti_con = { - .con_startup = sticon_startup, - .con_init = sticon_init, - .con_deinit = sticon_deinit, - .con_clear = sticon_clear, - .con_putc = sticon_putc, - .con_putcs = sticon_putcs, - .con_cursor = sticon_cursor, - .con_scroll = sticon_scroll, - .con_bmove = sticon_bmove, - .con_switch = sticon_switch, - .con_blank = sticon_blank, - .con_font_op = sticon_font_op, - .con_set_palette = sticon_set_palette, - .con_scrolldelta = sticon_scrolldelta, - .con_set_origin = sticon_set_origin, - .con_build_attr = sticon_build_attr, + con_startup: sticon_startup, + con_init: sticon_init, + con_deinit: sticon_deinit, + con_clear: sticon_clear, + con_putc: sticon_putc, + con_putcs: sticon_putcs, + con_cursor: sticon_cursor, + con_scroll: sticon_scroll, + con_bmove: sticon_bmove, + con_switch: sticon_switch, + con_blank: sticon_blank, + con_font_op: sticon_font_op, + con_set_palette: sticon_set_palette, + con_scrolldelta: sticon_scrolldelta, + con_set_origin: sticon_set_origin, + con_save_screen: sticon_save_screen, + con_build_attr: sticon_build_attr, + con_invert_region: sticon_invert_region, + con_screen_pos: sticon_screen_pos, + con_getxy: sticon_getxy, }; -static int __init sti_init(void) + + +int __init sticonsole_init(void) { - printk("searching for word mode STI ROMs\n"); - if (sti_init_roms()) { - pdc_console_die(); - take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1); - return 0; - } else - return -ENODEV; + if (sti_init_roms()) { + if (conswitchp == &dummy_con) { + printk(KERN_INFO "sticon: Initializing STI text console.\n"); + take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1); + } + return 0; + } else + return -ENODEV; } -module_init(sti_init) +module_init(sticonsole_init); diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index 8437e1570ed3..df348f124ffa 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -1,22 +1,40 @@ +/* + * linux/drivers/video/console/sticore.c - + * core code for console driver using HP's STI firmware + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * Portions Copyright (C) 2001-2002 Helge Deller <deller@gmx.de> + * Portions Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de> + * + * TODO: + * - call STI in virtual mode rather than in real mode + * - screen blanking with state_mgmt() in text mode STI ? + * - try to make it work on m68k hp workstations ;) + * - clean up the cache flushing functions + * + */ + +#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/pci.h> +#include <linux/font.h> -#include <asm/uaccess.h> #include <asm/pgalloc.h> -#include <asm/io.h> +#include <asm/hardware.h> -#include "sti.h" +#include "../sticore.h" -struct sti_struct default_sti = { - SPIN_LOCK_UNLOCKED, -}; +#define STI_DRIVERVERSION "0.9" + +struct sti_struct *default_sti; + +static int num_sti_roms; /* # of STI ROMS found */ +static struct sti_struct *sti_roms[MAX_STI_ROMS]; /* ptr to each sti_struct */ -static struct sti_font_flags default_font_flags = { - STI_WAIT, 0, 0, NULL -}; /* The colour indices used by STI are * 0 - Black @@ -31,31 +49,36 @@ static struct sti_font_flags default_font_flags = { * So we have the same colours as VGA (basically one bit each for R, G, B), * but have to translate them, anyway. */ -static u8 col_trans[8] = { +static const u8 col_trans[8] = { 0, 6, 4, 5, 2, 7, 3, 1 }; #define c_fg(sti, c) col_trans[((c>> 8) & 7)] #define c_bg(sti, c) col_trans[((c>>11) & 7)] -#define c_index(sti, c) (c&0xff) - -static struct sti_init_flags default_init_flags = { - STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL +#define c_index(sti, c) ((c) & 0xff) + +static const struct sti_init_flags default_init_flags = { + .wait = STI_WAIT, + .reset = 1, + .text = 1, + .nontext = 1, + .no_chg_bet = 1, + .no_chg_bei = 1, + .init_cmap_tx = 1, }; -void +int sti_init_graph(struct sti_struct *sti) { - struct sti_init_inptr_ext inptr_ext = { - 0, { 0 }, 0, NULL - }; + struct sti_init_inptr_ext inptr_ext = { 0, }; struct sti_init_inptr inptr = { - 3, STI_PTR(&inptr_ext) + 3, /* # of text planes (3 is maximum for STI) */ + STI_PTR(&inptr_ext) }; - struct sti_init_outptr outptr = { 0 }; + struct sti_init_outptr outptr = { 0, }; unsigned long flags; - s32 ret; + int ret; spin_lock_irqsave(&sti->lock, flags); @@ -64,42 +87,50 @@ sti_init_graph(struct sti_struct *sti) spin_unlock_irqrestore(&sti->lock, flags); + if (ret < 0) { + printk(KERN_ERR "STI init_graph failed (ret %d, errno %d)\n",ret,outptr.errno); + return -1; + } + sti->text_planes = outptr.text_planes; + return 0; } -static struct sti_conf_flags default_conf_flags = { - STI_WAIT, 0, NULL -}; +static const struct sti_conf_flags default_conf_flags = { + wait: STI_WAIT, + }; void sti_inq_conf(struct sti_struct *sti) { - struct sti_conf_inptr inptr = { NULL }; - struct sti_conf_outptr_ext outptr_ext = { .future_ptr = NULL }; - struct sti_conf_outptr outptr = { - .ext_ptr = STI_PTR(&outptr_ext) - }; + struct sti_conf_inptr inptr = { 0 }; unsigned long flags; s32 ret; + + sti->outptr.ext_ptr = STI_PTR(&sti->outptr_ext); do { spin_lock_irqsave(&sti->lock, flags); ret = STI_CALL(sti->inq_conf, &default_conf_flags, - &inptr, &outptr, sti->glob_cfg); + &inptr, &sti->outptr, sti->glob_cfg); spin_unlock_irqrestore(&sti->lock, flags); - } while(ret == 1); + } while (ret == 1); } +static const struct sti_font_flags default_font_flags = { + wait: STI_WAIT, + non_text: 0, +}; + void sti_putc(struct sti_struct *sti, int c, int y, int x) { struct sti_font_inptr inptr = { - (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c), - x * sti_font_x(sti), y * sti_font_y(sti), NULL - }; - struct sti_font_outptr outptr = { - 0, NULL + STI_PTR(sti->font->raw), + c_index(sti, c), c_fg(sti, c), c_bg(sti, c), + x * sti->font_width, y * sti->font_height, 0 }; + struct sti_font_outptr outptr = { 0, }; s32 ret; unsigned long flags; @@ -108,11 +139,13 @@ sti_putc(struct sti_struct *sti, int c, int y, int x) ret = STI_CALL(sti->font_unpmv, &default_font_flags, &inptr, &outptr, sti->glob_cfg); spin_unlock_irqrestore(&sti->lock, flags); - } while(ret == 1); + } while (ret == 1); } -static struct sti_blkmv_flags clear_blkmv_flags = { - STI_WAIT, 1, 1, 0, 0, NULL +static const struct sti_blkmv_flags clear_blkmv_flags = { + .wait = STI_WAIT, + .color = 1, + .clear = 1, }; void @@ -124,10 +157,10 @@ sti_set(struct sti_struct *sti, int src_y, int src_x, src_x, src_y , src_x, src_y , width, height, - NULL + 0 }; - struct sti_blkmv_outptr outptr = { 0, NULL }; - s32 ret = 0; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; unsigned long flags; do { @@ -135,22 +168,22 @@ sti_set(struct sti_struct *sti, int src_y, int src_x, ret = STI_CALL(sti->block_move, &clear_blkmv_flags, &inptr, &outptr, sti->glob_cfg); spin_unlock_irqrestore(&sti->lock, flags); - } while(ret == 1); + } while (ret == 1); } void sti_clear(struct sti_struct *sti, int src_y, int src_x, - int height, int width) + int height, int width, int c) { struct sti_blkmv_inptr inptr = { - 0, 0, - src_x * sti_font_x(sti), src_y * sti_font_y(sti), - src_x * sti_font_x(sti), src_y * sti_font_y(sti), - width * sti_font_x(sti), height* sti_font_y(sti), - NULL + c_fg(sti, c), c_bg(sti, c), + src_x * sti->font_width, src_y * sti->font_height, + src_x * sti->font_width, src_y * sti->font_height, + width * sti->font_width, height* sti->font_height, + 0 }; - struct sti_blkmv_outptr outptr = { 0, NULL }; - s32 ret = 0; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; unsigned long flags; do { @@ -158,11 +191,11 @@ sti_clear(struct sti_struct *sti, int src_y, int src_x, ret = STI_CALL(sti->block_move, &clear_blkmv_flags, &inptr, &outptr, sti->glob_cfg); spin_unlock_irqrestore(&sti->lock, flags); - } while(ret == 1); + } while (ret == 1); } -static struct sti_blkmv_flags default_blkmv_flags = { - STI_WAIT, 0, 0, 0, 0, NULL +static const struct sti_blkmv_flags default_blkmv_flags = { + .wait = STI_WAIT, }; void @@ -171,13 +204,13 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x, { struct sti_blkmv_inptr inptr = { 0, 0, - src_x * sti_font_x(sti), src_y * sti_font_y(sti), - dst_x * sti_font_x(sti), dst_y * sti_font_y(sti), - width * sti_font_x(sti), height* sti_font_y(sti), - NULL + src_x * sti->font_width, src_y * sti->font_height, + dst_x * sti->font_width, dst_y * sti->font_height, + width * sti->font_width, height* sti->font_height, + 0 }; - struct sti_blkmv_outptr outptr = { 0, NULL }; - s32 ret = 0; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; unsigned long flags; do { @@ -185,170 +218,128 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x, ret = STI_CALL(sti->block_move, &default_blkmv_flags, &inptr, &outptr, sti->glob_cfg); spin_unlock_irqrestore(&sti->lock, flags); - } while(ret == 1); + } while (ret == 1); } -static void __init -sti_rom_copy(unsigned long base, unsigned long offset, - unsigned long count, void *dest) +void __init +sti_rom_copy(unsigned long base, unsigned long count, void *dest) { - void *savedest = dest; - int savecount = count; + unsigned long dest_len = count; + unsigned long dest_start = (unsigned long) dest; - while(count >= 4) { + /* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */ + while (count >= 4) { count -= 4; - *(u32 *)dest = gsc_readl(base + offset); - offset += 4; + *(u32 *)dest = __raw_readl(base); + base += 4; dest += 4; } - while(count) { + while (count) { count--; - *(u8 *)dest = gsc_readb(base + offset); - offset++; + *(u8 *)dest = __raw_readb(base); + base++; dest++; } - flush_kernel_dcache_range((unsigned long)dest, count); - flush_icache_range((unsigned long)dest, dest + count); -} - -static void dump_sti_rom(struct sti_rom *rom) -{ - printk("STI word mode ROM type %d\n", rom->type[3]); - printk(" supports %d monitors\n", rom->num_mons); - printk(" conforms to STI ROM spec revision %d.%02x\n", - rom->revno[0] >> 4, rom->revno[0] & 0x0f); - printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n", - rom->graphics_id[0], - rom->graphics_id[1], - rom->graphics_id[2], - rom->graphics_id[3], - rom->graphics_id[4], - rom->graphics_id[5], - rom->graphics_id[6], - rom->graphics_id[7]); - printk(" font start %08x\n", rom->font_start); - printk(" region list %08x\n", rom->region_list); - printk(" init_graph %08x\n", rom->init_graph); - printk(" alternate code type %d\n", rom->alt_code_type); + sti_flush(dest_start, dest_len); /* XXX */ } -static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom, - struct sti_rom *raw_rom) -{ - struct sti_rom_font *raw_font; - struct sti_cooked_font *cooked_font; - struct sti_rom_font *font_start; - - cooked_font = - kmalloc(sizeof *cooked_font, GFP_KERNEL); - if(!cooked_font) - return; - cooked_rom->font_start = cooked_font; - raw_font = ((void *)raw_rom) + (raw_rom->font_start); - font_start = raw_font; - cooked_font->raw = raw_font; +static char default_sti_path[21]; - while(raw_font->next_font) { - raw_font = ((void *)font_start) + (raw_font->next_font); - - cooked_font->next_font = - kmalloc(sizeof *cooked_font, GFP_KERNEL); - if(!cooked_font->next_font) - return; +static int __init +sti_setup(char *str) +{ + if (str) + strncpy (default_sti_path, str, sizeof (default_sti_path)); + + return 0; +} - cooked_font = cooked_font->next_font; +/* Assuming the machine has multiple STI consoles (=graphic cards) which + * all get detected by sticon, the user may define with the linux kernel + * parameter sti=<x> which of them will be the initial boot-console. + * <x> is a number between 0 and MAX_STI_ROMS, with 0 as the default + * STI screen. + */ +__setup("sti=", sti_setup); - cooked_font->raw = raw_font; - } - cooked_font->next_font = NULL; -} -static int font_index, font_height, font_width; +static char __initdata *font_name[MAX_STI_ROMS] = { "VGA8x16", }; +static int __initdata font_index[MAX_STI_ROMS], + font_height[MAX_STI_ROMS], + font_width[MAX_STI_ROMS]; static int __init sti_font_setup(char *str) { char *x; + int i = 0; - /* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style - * command lines. */ - - if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) { - font_height = simple_strtoul(str, NULL, 0); - font_width = simple_strtoul(x+1, NULL, 0); - } else { - font_index = simple_strtoul(str, NULL, 0); - } - - return 0; -} + /* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 + * or sti_font=7 style command lines. */ + + while (i<MAX_STI_ROMS && str && *str) { + if (*str>='0' && *str<='9') { + if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) { + font_height[i] = simple_strtoul(str, NULL, 0); + font_width[i] = simple_strtoul(x+1, NULL, 0); + } else { + font_index[i] = simple_strtoul(str, NULL, 0); + } + } else { + font_name[i] = str; /* fb font name */ + } -__setup("sti_font=", sti_font_setup); + if ((x = strchr(str, ','))) + *x++ = 0; + str = x; -static int __init sti_search_font(struct sti_cooked_rom *rom, - int height, int width) -{ - struct sti_cooked_font *font; - int i = 0; - - for(font = rom->font_start; font; font = font->next_font, i++) { - if((font->raw->width == width) && (font->raw->height == height)) - return i; + i++; } return 0; } -static struct sti_cooked_font * __init -sti_select_font(struct sti_cooked_rom *rom) -{ - struct sti_cooked_font *font; - int i; - - if(font_width && font_height) - font_index = sti_search_font(rom, font_height, font_width); +/* The optional linux kernel parameter "sti_font" defines which font + * should be used by the sticon driver to draw characters to the screen. + * Possible values are: + * - sti_font=<fb_fontname>: + * <fb_fontname> is the name of one of the linux-kernel built-in + * framebuffer font names (e.g. VGA8x16, SUN22x18). + * This is only available if the fonts have been statically compiled + * in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options. + * - sti_font=<number> + * most STI ROMs have built-in HP specific fonts, which can be selected + * by giving the desired number to the sticon driver. + * NOTE: This number is machine and STI ROM dependend. + * - sti_font=<height>x<width> (e.g. sti_font=16x8) + * <height> and <width> gives hints to the height and width of the + * font which the user wants. The sticon driver will try to use + * a font with this height and width, but if no suitable font is + * found, sticon will use the default 8x8 font. + */ +__setup("sti_font=", sti_font_setup); - for(font = rom->font_start, i = font_index; - font && (i > 0); - font = font->next_font, i--); - if(font) - return font; - else - return rom->font_start; -} -static void __init -sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg) -{ - printk( "monitor %d\n" - "in friendly mode: %d\n" - "power consumption %d watts\n" - "freq ref %d\n" - "sti_mem_addr %p\n", - cfg->curr_mon, - cfg->friendly_boot, - cfg->power, - cfg->freq_ref, - cfg->sti_mem_addr); -} - void __init -sti_dump_globcfg(struct sti_glob_cfg *glob_cfg) +sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) { - printk( "%d text planes\n" + struct sti_glob_cfg_ext *cfg; + + DPRINTK((KERN_INFO + "%d text planes\n" "%4d x %4d screen resolution\n" "%4d x %4d offscreen\n" "%4d x %4d layout\n" "regions at %08x %08x %08x %08x\n" "regions at %08x %08x %08x %08x\n" "reent_lvl %d\n" - "save_addr %p\n", + "save_addr %08x\n", glob_cfg->text_planes, glob_cfg->onscreen_x, glob_cfg->onscreen_y, glob_cfg->offscreen_x, glob_cfg->offscreen_y, @@ -358,105 +349,420 @@ sti_dump_globcfg(struct sti_glob_cfg *glob_cfg) glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5], glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7], glob_cfg->reent_lvl, - glob_cfg->save_addr); - sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr)); + glob_cfg->save_addr)); + + /* dump extended cfg */ + cfg = PTR_STI(glob_cfg->ext_ptr); + DPRINTK(( KERN_INFO + "monitor %d\n" + "in friendly mode: %d\n" + "power consumption %d watts\n" + "freq ref %d\n" + "sti_mem_addr %08x (size=%d bytes)\n", + cfg->curr_mon, + cfg->friendly_boot, + cfg->power, + cfg->freq_ref, + cfg->sti_mem_addr, sti_mem_request)); } - -static void __init -sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa, - unsigned long rom_address) + +void __init +sti_dump_outptr(struct sti_struct *sti) +{ + DPRINTK((KERN_INFO + "%d bits per pixel\n" + "%d used bits\n" + "%d planes\n" + "attributes %08x\n", + sti->outptr.bits_per_pixel, + sti->outptr.bits_used, + sti->outptr.planes, + sti->outptr.attributes)); +} + +int __init +sti_init_glob_cfg(struct sti_struct *sti, + unsigned long rom_address, unsigned long hpa) { struct sti_glob_cfg *glob_cfg; struct sti_glob_cfg_ext *glob_cfg_ext; void *save_addr; void *sti_mem_addr; + const int save_addr_size = 1024; /* XXX */ + int i; + + if (!sti->sti_mem_request) + sti->sti_mem_request = 256; /* STI default */ - glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL); - glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL); - save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL); - sti_mem_addr = kmalloc(1024, GFP_KERNEL); + glob_cfg = kmalloc(sizeof(*sti->glob_cfg), GFP_KERNEL); + glob_cfg_ext = kmalloc(sizeof(*glob_cfg_ext), GFP_KERNEL); + save_addr = kmalloc(save_addr_size, GFP_KERNEL); + sti_mem_addr = kmalloc(sti->sti_mem_request, GFP_KERNEL); - if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr)) - return; + if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr)) + return -ENOMEM; - memset(glob_cfg, 0, sizeof *glob_cfg); - memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext); - memset(save_addr, 0, 1024); - memset(sti_mem_addr, 0, 1024); + memset(glob_cfg, 0, sizeof(*glob_cfg)); + memset(glob_cfg_ext, 0, sizeof(*glob_cfg_ext)); + memset(save_addr, 0, save_addr_size); + memset(sti_mem_addr, 0, sti->sti_mem_request); glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext); glob_cfg->save_addr = STI_PTR(save_addr); - glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address; - glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa; - glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa; - glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa; - glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa; - glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa; - glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa; - glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa; - + for (i=0; i<8; i++) { + unsigned long newhpa, len; + + if (sti->pd) { + unsigned char offs = sti->rm_entry[i]; + + if (offs == 0) + continue; + if (offs != PCI_ROM_ADDRESS && + (offs < PCI_BASE_ADDRESS_0 || + offs > PCI_BASE_ADDRESS_5)) { + printk (KERN_WARNING + "STI pci region maping for region %d (%02x) can't be mapped\n", + i,sti->rm_entry[i]); + continue; + } + newhpa = pci_resource_start (sti->pd, (offs - PCI_BASE_ADDRESS_0) / 4); + } else + newhpa = (i == 0) ? rom_address : hpa; + + sti->regions_phys[i] = + REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa); + + /* remap virtually */ + /* FIXME: add BTLB support if btlb==1 */ + len = sti->regions[i].region_desc.length * 4096; + + if (len) + glob_cfg->region_ptrs[i] = (unsigned long) ( + sti->regions[i].region_desc.cache ? + ioremap(sti->regions_phys[i], len) : + ioremap_nocache(sti->regions_phys[i], len) ); + + DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, " + "btlb=%d, sysonly=%d, cache=%d, last=%d\n", + i, sti->regions_phys[i], glob_cfg->region_ptrs[i], + len/1024, + sti->regions[i].region_desc.btlb, + sti->regions[i].region_desc.sys_only, + sti->regions[i].region_desc.cache, + sti->regions[i].region_desc.last)); + + /* last entry reached ? */ + if (sti->regions[i].region_desc.last) + break; + } + + if (++i<8 && sti->regions[i].region) + printk(KERN_WARNING "%s: *future ptr (0x%8x) not yet supported !\n", + __FILE__, sti->regions[i].region); + glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr); - sti->glob_cfg = STI_PTR(glob_cfg); + sti->glob_cfg = glob_cfg; + + return 0; } -/* address is a pointer to a word mode or pci rom */ -static struct sti_struct * __init -sti_read_rom(unsigned long address) +#ifdef CONFIG_FB +struct sti_cooked_font * __init +sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) { - struct sti_struct *ret = NULL; - struct sti_cooked_rom *cooked = NULL; - struct sti_rom *raw = NULL; - unsigned long size; + struct font_desc *fbfont; + unsigned int size, bpc; + void *dest; + struct sti_rom_font *nf; + struct sti_cooked_font *cooked_font; + + if (!fbfont_name || !strlen(fbfont_name)) + return NULL; + fbfont = find_font(fbfont_name); + if (!fbfont) + fbfont = get_default_font(1024,768); + if (!fbfont) + return NULL; + + DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n", + fbfont->width, fbfont->height, fbfont->name)); + + bpc = ((fbfont->width+7)/8) * fbfont->height; + size = bpc * 256; + size += sizeof(struct sti_rom_font); + + nf = kmalloc(size, GFP_KERNEL); + if (!nf) + return NULL; + memset(nf, 0, size); + + nf->first_char = 0; + nf->last_char = 255; + nf->width = fbfont->width; + nf->height = fbfont->height; + nf->font_type = STI_FONT_HPROMAN8; + nf->bytes_per_char = bpc; + nf->next_font = 0; + nf->underline_height = 1; + nf->underline_pos = fbfont->height - nf->underline_height; + + dest = nf; + dest += sizeof(struct sti_rom_font); + memcpy(dest, fbfont->data, bpc*256); + + cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); + if (!cooked_font) { + kfree(nf); + return NULL; + } + + cooked_font->raw = nf; + cooked_font->next_font = NULL; - ret = &default_sti; + cooked_rom->font_start = cooked_font; - if(!ret) - goto out_err; + return cooked_font; +} +#else +struct sti_cooked_font * __init +sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name) +{ + return NULL; +} +#endif - cooked = kmalloc(sizeof *cooked, GFP_KERNEL); - raw = kmalloc(sizeof *raw, GFP_KERNEL); +struct sti_cooked_font * __init +sti_select_font(struct sti_cooked_rom *rom, + int (*search_font_fnc) (struct sti_cooked_rom *,int,int) ) +{ + struct sti_cooked_font *font; + int i; + int index = num_sti_roms; + + /* check for framebuffer-font first */ + if ((font = sti_select_fbfont(rom, font_name[index]))) + return font; + + if (font_width[index] && font_height[index]) + font_index[index] = search_font_fnc(rom, + font_height[index], font_width[index]); + + for (font = rom->font_start, i = font_index[index]; + font && (i > 0); + font = font->next_font, i--); + + if (font) + return font; + else + return rom->font_start; +} + + +static void __init +sti_dump_rom(struct sti_rom *rom) +{ + printk(KERN_INFO "STI id %04x-%04x, conforms to spec rev. %d.%02x\n", + rom->graphics_id[0], + rom->graphics_id[1], + rom->revno[0] >> 4, + rom->revno[0] & 0x0f); + DPRINTK((" supports %d monitors\n", rom->num_mons)); + DPRINTK((" font start %08x\n", rom->font_start)); + DPRINTK((" region list %08x\n", rom->region_list)); + DPRINTK((" init_graph %08x\n", rom->init_graph)); + DPRINTK((" bus support %02x\n", rom->bus_support)); + DPRINTK((" ext bus support %02x\n", rom->ext_bus_support)); + DPRINTK((" alternate code type %d\n", rom->alt_code_type)); +} + + +static int __init +sti_cook_fonts(struct sti_cooked_rom *cooked_rom, + struct sti_rom *raw_rom) +{ + struct sti_rom_font *raw_font, *font_start; + struct sti_cooked_font *cooked_font; - if(!(raw && cooked)) - goto out_err; + cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); + if (!cooked_font) + return 0; - /* reallocate raw */ - sti_rom_copy(address, 0, sizeof *raw, raw); + cooked_rom->font_start = cooked_font; - dump_sti_rom(raw); + raw_font = ((void *)raw_rom) + (raw_rom->font_start); - size = raw->last_addr; - /* kfree(raw); */ - raw = kmalloc(size, GFP_KERNEL); - if(!raw) - goto out_err; - sti_rom_copy(address, 0, size, raw); + font_start = raw_font; + cooked_font->raw = raw_font; - sti_cook_fonts(cooked, raw); -#if 0 - sti_cook_regions(cooked, raw); - sti_cook_functions(cooked, raw); -#endif + while (raw_font->next_font) { + raw_font = ((void *)font_start) + (raw_font->next_font); + + cooked_font->next_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); + if (!cooked_font->next_font) + return 1; + + cooked_font = cooked_font->next_font; + + cooked_font->raw = raw_font; + } + + cooked_font->next_font = NULL; + return 1; +} + + +static int __init +sti_search_font(struct sti_cooked_rom *rom, int height, int width) +{ + struct sti_cooked_font *font; + int i = 0; + + for(font = rom->font_start; font; font = font->next_font, i++) { + if((font->raw->width == width) && (font->raw->height == height)) + return i; + } + return 0; +} + +#define BMODE_RELOCATE(offset) offset = (offset) / 4; +#define BMODE_LAST_ADDR_OFFS 0x50 + +static void * __init +sti_bmode_font_raw(struct sti_cooked_font *f) +{ + unsigned char *n, *p, *q; + int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font); + + n = kmalloc (4*size, GFP_KERNEL); + if (!n) + return NULL; + memset (n, 0, 4*size); + p = n + 3; + q = (unsigned char *)f->raw; + while (size--) { + *p = *q++; + p+=4; + } + return n + 3; +} - if(raw->region_list) { - ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */ +static void __init +sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest) +{ + unsigned long dest_len = count; + unsigned long dest_start = (unsigned long) dest; - memcpy(ret->regions, ((void *)raw)+raw->region_list, 32); + while (count) { + count--; + *(u8 *)dest = __raw_readl(base); + base += 4; + dest++; } + sti_flush(dest_start, dest_len); /* XXX */ +} - address = virt_to_phys(raw); +struct sti_rom * __init +sti_get_bmode_rom (unsigned long address) +{ + struct sti_rom *raw; + u32 size; + struct sti_rom_font *raw_font, *font_start; + + sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); + + size = (size+3) / 4; + raw = kmalloc(size, GFP_KERNEL); + if (raw) { + sti_bmode_rom_copy(address, size, raw); + memmove (&raw->res004, &raw->type[0], 0x3c); + raw->type[3] = raw->res004; + + BMODE_RELOCATE (raw->region_list); + BMODE_RELOCATE (raw->font_start); + + BMODE_RELOCATE (raw->init_graph); + BMODE_RELOCATE (raw->state_mgmt); + BMODE_RELOCATE (raw->font_unpmv); + BMODE_RELOCATE (raw->block_move); + BMODE_RELOCATE (raw->inq_conf); + + raw_font = ((void *)raw) + raw->font_start; + font_start = raw_font; + + while (raw_font->next_font) { + BMODE_RELOCATE (raw_font->next_font); + raw_font = ((void *)font_start) + raw_font->next_font; + } + } + return raw; +} - ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff); - ret->block_move = address+(raw->block_move & 0x03ffffff); - ret->init_graph = address+(raw->init_graph & 0x03ffffff); - ret->inq_conf = address+(raw->inq_conf & 0x03ffffff); +struct sti_rom * __init +sti_get_wmode_rom (unsigned long address) +{ + struct sti_rom *raw; + unsigned long size; + + /* read the ROM size directly from the struct in ROM */ + size = __raw_readl(address + offsetof(struct sti_rom,last_addr)); - ret->rom = cooked; - ret->rom->raw = raw; + raw = kmalloc(size, GFP_KERNEL); + if(raw) + sti_rom_copy(address, size, raw); - ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw); + return raw; +} - return ret; +int __init +sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) +{ + struct sti_cooked_rom *cooked; + struct sti_rom *raw = NULL; + + cooked = kmalloc(sizeof *cooked, GFP_KERNEL); + if (!cooked) + goto out_err; + + if (wordmode) + raw = sti_get_wmode_rom (address); + else + raw = sti_get_bmode_rom (address); + + if (!raw) + goto out_err; + + if (!sti_cook_fonts(cooked, raw)) { + printk(KERN_ERR "No font found for STI at %08lx\n", address); + goto out_err; + } + + if (raw->region_list) + memcpy(sti->regions, ((void *)raw)+raw->region_list, sizeof(sti->regions)); + + address = (unsigned long) STI_PTR(raw); + + sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff); + sti->block_move = address + (raw->block_move & 0x03ffffff); + sti->init_graph = address + (raw->init_graph & 0x03ffffff); + sti->inq_conf = address + (raw->inq_conf & 0x03ffffff); + + sti->rom = cooked; + sti->rom->raw = raw; + + sti->font = sti_select_font(sti->rom, sti_search_font); + sti->font_width = sti->font->raw->width; + sti->font_height = sti->font->raw->height; + if (!wordmode) + sti->font->raw = sti_bmode_font_raw(sti->font); + + sti->sti_mem_request = raw->sti_mem_req; + sti->graphics_id[0] = raw->graphics_id[0]; + sti->graphics_id[1] = raw->graphics_id[1]; + + sti_dump_rom(raw); + + return 1; out_err: if(raw) @@ -464,138 +770,290 @@ out_err: if(cooked) kfree(cooked); - return NULL; + return 0; } static struct sti_struct * __init -sti_try_rom(unsigned long address, unsigned long hpa) +sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd) { - struct sti_struct *sti = NULL; - u16 sig; + struct sti_struct *sti; + int ok; + u32 sig; + + if (num_sti_roms >= MAX_STI_ROMS) { + printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); + return NULL; + } + sti = kmalloc(sizeof(*sti), GFP_KERNEL); + if (!sti) { + printk(KERN_ERR "Not enough memory !\n"); + return NULL; + } + + memset(sti, 0, sizeof(*sti)); + sti->lock = SPIN_LOCK_UNLOCKED; + test_rom: /* if we can't read the ROM, bail out early. Not being able * to read the hpa is okay, for romless sti */ - if(pdc_add_valid((void*)address)) - return NULL; - - printk("found potential STI ROM at %08lx\n", address); - - sig = le16_to_cpu(gsc_readw(address)); + if (pdc_add_valid(address)) + goto out_err; - if((sig==0x55aa) || (sig==0xaa55)) { - address += le32_to_cpu(gsc_readl(address+8)); - printk("sig %04x, PCI STI ROM at %08lx\n", - sig, address); + sig = __raw_readl(address); + + /* check for a PCI ROM structure */ + if ((le32_to_cpu(sig)==0xaa55)) { + unsigned int i, rm_offset; + u32 *rm; + i = __raw_readl(address+0x04); + if (i != 1) { + /* The ROM could have multiple architecture + * dependent images (e.g. i386, parisc,...) */ + printk(KERN_WARNING + "PCI ROM is not a STI ROM type image (0x%8x)\n", i); + goto out_err; + } + + sti->pd = pd; + + i = __raw_readl(address+0x0c); + DPRINTK(("PCI ROM size (from header) = %d kB\n", + le16_to_cpu(i>>16)*512/1024)); + rm_offset = le16_to_cpu(i & 0xffff); + if (rm_offset) { + /* read 16 bytes from the pci region mapper array */ + rm = (u32*) &sti->rm_entry; + *rm++ = __raw_readl(address+rm_offset+0x00); + *rm++ = __raw_readl(address+rm_offset+0x04); + *rm++ = __raw_readl(address+rm_offset+0x08); + *rm++ = __raw_readl(address+rm_offset+0x0c); + DPRINTK(("PCI region Mapper offset = %08x: ", + rm_offset)); + for (i=0; i<16; i++) + DPRINTK(("%02x ", sti->rm_entry[i])); + DPRINTK(("\n")); + } + address += le32_to_cpu(__raw_readl(address+8)); + DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address)); goto test_rom; } - - if((sig&0xff) == 0x01) { - printk("STI byte mode ROM at %08lx, ignored\n", - address); - - sti = NULL; + + ok = 0; + + if ((sig & 0xff) == 0x01) { + printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n", + address, hpa); + ok = sti_read_rom(0, sti, address); } - if(sig == 0x0303) { - printk("STI word mode ROM at %08lx\n", - address); - - sti = sti_read_rom(address); + if ((sig & 0xffff) == 0x0303) { + printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n", + address, hpa); + ok = sti_read_rom(1, sti, address); } - if (!sti) - return NULL; + if (!ok) + goto out_err; - /* this is hacked. We need a better way to find out the HPA for - * romless STI (eg search for the graphics devices we know about - * by sversion) */ - if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n"); - if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n"); - if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n"); - if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n"); - sti_init_glob_cfg(sti, hpa, address); + if (sti_init_glob_cfg(sti, address, hpa)) + goto out_err; /* not enough memory */ + + /* disable STI PCI ROM. ROM and card RAM overlap and + * leaving it enabled would force HPMCs + */ + if (sti->pd) { + unsigned long rom_base; + rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE); + pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE); + DPRINTK((KERN_DEBUG "STI PCI ROM disabled\n")); + } - sti_init_graph(sti); + if (sti_init_graph(sti)) + goto out_err; sti_inq_conf(sti); - sti_dump_globcfg(PTR_STI(sti->glob_cfg)); + sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request); + sti_dump_outptr(sti); + + printk(KERN_INFO "STI device: %s\n", sti->outptr.dev_name ); + sti_roms[num_sti_roms] = sti; + num_sti_roms++; + return sti; + +out_err: + kfree(sti); + return NULL; } -static unsigned long sti_address; -static unsigned long sti_hpa; +static void __init sticore_check_for_default_sti (struct sti_struct *sti, char *path) +{ + if (strcmp (path, default_sti_path) == 0) + default_sti = sti; +} -/* XXX: should build a list of STI ROMs */ -struct sti_struct * __init -sti_init_roms(void) +/* + * on newer systems PDC gives the address of the ROM + * in the additional address field addr[1] while on + * older Systems the PDC stores it in page0->proc_sti + */ +static int __init sticore_pa_init(struct parisc_device *dev) { - struct sti_struct *tmp = NULL, *sti = NULL; + unsigned long rom = 0; + char pa_path[21]; + struct sti_struct *sti = NULL; + + if(dev->num_addrs) { + rom = dev->addr[0]; + } + if (!rom) { + rom = dev->hpa; + DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); + sti = sti_try_rom_generic(rom, dev->hpa, NULL); + rom = PAGE0->proc_sti; + } + if (!sti) { + DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); + sti = sti_try_rom_generic(rom, dev->hpa, NULL); + } + if (!sti) + return 1; + + print_pa_hwpath(dev, pa_path); + sticore_check_for_default_sti (sti, pa_path); + return 0; +} + - /* handle the command line */ - if (sti_address && sti_hpa) { - return sti_try_rom(sti_address, sti_hpa); +static int __devinit sticore_pci_init(struct pci_dev *pd, + const struct pci_device_id *ent) +{ +#ifdef CONFIG_PCI + unsigned long fb_base, rom_base; + unsigned int fb_len, rom_len; + struct sti_struct *sti; + + pci_enable_device(pd); + + fb_base = pci_resource_start(pd, 0); + fb_len = pci_resource_len(pd, 0); + rom_base = pci_resource_start(pd, PCI_ROM_RESOURCE); + rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE); + if (rom_base) { + pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE); + DPRINTK((KERN_DEBUG "STI PCI ROM enabled at 0x%08lx\n", rom_base)); } - /* 712, 715, some other boxes don't have a separate STI ROM, - * but use part of the regular flash */ - if (PAGE0->proc_sti) { - printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti); - if (!pdc_add_valid((void *)0xf9000000)) - sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000); - else if (!pdc_add_valid((void *)0xf5000000)) - sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000); - else if (!pdc_add_valid((void *)0xf7000000)) - sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000); - else if (!pdc_add_valid((void *)0xfb000000)) - sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000); + printk(KERN_INFO "STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n", + rom_base, rom_len/1024, fb_base, fb_len/1024/1024); + + DPRINTK((KERN_DEBUG "Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n", + rom_base, fb_base)); + sti = sti_try_rom_generic(rom_base, fb_base, pd); + if (sti) { + char pa_path[30]; + print_pci_hwpath(pd, pa_path); + sticore_check_for_default_sti(sti, pa_path); } + + if (!sti) { + printk(KERN_WARNING "Unable to handle STI device '%s'\n", + pd->dev.name); + return -ENODEV; + } +#endif /* CONFIG_PCI */ + + return 0; +} - /* standard locations for GSC graphic devices */ - if (!pdc_add_valid((void *)0xf4000000)) - tmp = sti_try_rom(0xf4000000, 0xf4000000); - sti = tmp ? tmp : sti; - if (!pdc_add_valid((void *)0xf6000000)) - tmp = sti_try_rom(0xf6000000, 0xf6000000); - sti = tmp ? tmp : sti; - if (!pdc_add_valid((void *)0xf8000000)) - tmp = sti_try_rom(0xf8000000, 0xf8000000); - sti = tmp ? tmp : sti; - if (!pdc_add_valid((void *)0xfa000000)) - tmp = sti_try_rom(0xfa000000, 0xfa000000); - sti = tmp ? tmp : sti; - return sti; +static void __devexit sticore_pci_remove(struct pci_dev *pd) +{ + BUG(); } -static int __init -sti_setup(char *str) + +#define PCI_DEVICE_ID_VISUALIZE_EG 0x1005 +#define PCI_DEVICE_ID_VISUALIZE_FX 0x1008 +#define PCI_DEVICE_ID_VISUALIZE_FX_NEW 0x108b + +static struct pci_device_id sti_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_EG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX_NEW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, sti_pci_tbl); + +static struct pci_driver pci_sti_driver = { + .name = "sti (pci)", + .id_table = sti_pci_tbl, + .probe = sticore_pci_init, + .remove = sticore_pci_remove, +}; + +static struct parisc_device_id sti_pa_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00077 }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00085 }, + { 0, } +}; + +struct parisc_driver pa_sti_driver = { + .name = "sti (native)", + .id_table = sti_pa_tbl, + .probe = sticore_pa_init, +}; + +struct sti_struct * __init sti_init_roms(void) { - char *end; + static int initialized; - if(strcmp(str, "pdc") == 0) { - sti_address = PAGE0->proc_sti; + if (initialized) + goto out; - return 1; - } else { - sti_address = simple_strtoul(str, &end, 16); + printk(KERN_INFO "STI GSC/PCI graphics driver version %s\n", + STI_DRIVERVERSION); - if((end == str) || (sti_address < 0xf0000000)) { - sti_address = 0; - return 0; - } + /* Register drivers for native & PCI cards */ + register_parisc_driver(&pa_sti_driver); + pci_module_init (&pci_sti_driver); - sti_hpa = sti_address; + /* if we didn't find the given default sti, take the first one */ + if (!default_sti) + default_sti = sti_roms[0]; - return 1; +out: + /* return default STI if available */ + if (num_sti_roms && default_sti && default_sti->init_graph) { + initialized = 1; + return default_sti; } - - return 0; + return NULL; } -__setup("sti=", sti_setup); - -MODULE_LICENSE("GPL"); +/* + * index = 0 gives default sti + * index > 0 gives other stis in detection order + */ +struct sti_struct * __init sti_get_rom(int index) +{ + int i; + + if (index == 0) + return default_sti; + + i = -1; + while (index > 0) { + i++; + if (i > num_sti_roms) + return NULL; + if (sti_roms[i] == default_sti) + continue; + index--; + } + return sti_roms[i]; +} diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 19031e2573f6..69bb72d5777a 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -22,6 +22,10 @@ * control.c: Console support for PowerMac "control" display adaptor. * Copyright (C) 1996 Paul Mackerras * + * Updated to 2.5 framebuffer API by Ben Herrenschmidt + * <benh@kernel.crashing.org>, Paul Mackerras <paulus@samba.org>, + * and James Simmons <jsimmons@infradead.org>. + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. @@ -50,12 +54,7 @@ #include <asm/pgtable.h> #include <asm/btext.h> -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-cfb32.h> -#include <video/macmodes.h> - +#include "macmodes.h" #include "controlfb.h" struct fb_par_control { @@ -97,7 +96,6 @@ static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninf struct fb_info_control { struct fb_info info; - struct display display; /* Will disappear */ struct fb_par_control par; u32 pseudo_palette[17]; @@ -119,14 +117,14 @@ struct fb_info_control { }; /* control register access macro */ -#define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs-> ## REG).r)) +#define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs->REG).r)) /******************** Prototypes for exported functions ********************/ /* * struct fb_ops */ -static int controlfb_pan_display(struct fb_var_screeninfo *var, int con, +static int controlfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); @@ -171,11 +169,8 @@ static int default_cmode __initdata = CMODE_NVRAM; static struct fb_ops controlfb_ops = { .owner = THIS_MODULE, - .fb_set_var = gen_set_var, .fb_check_var = controlfb_check_var, .fb_set_par = controlfb_set_par, - .fb_get_cmap = gen_get_cmap, - .fb_set_cmap = gen_set_cmap, .fb_setcolreg = controlfb_setcolreg, .fb_pan_display = controlfb_pan_display, .fb_blank = controlfb_blank, @@ -265,8 +260,8 @@ static inline void set_screen_start(int xoffset, int yoffset, } -static int controlfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +static int controlfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { unsigned int xoffset, hstep; struct fb_info_control *p = (struct fb_info_control *)info; @@ -483,7 +478,7 @@ try_again: /* Apply default var */ p->info.var = var; var.activate = FB_ACTIVATE_NOW; - rc = gen_set_var(&var, -1, &p->info); + rc = fb_set_var(&var, &p->info); if (rc && (vmode != VMODE_640_480_60 || cmode != CMODE_8)) goto try_again; @@ -491,7 +486,7 @@ try_again: if (register_framebuffer(&p->info) < 0) return -ENXIO; - printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); + printk(KERN_INFO "fb%d: control display adapter\n", minor(p->info.node)); return 0; } @@ -1015,22 +1010,12 @@ static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeni static void __init control_init_info(struct fb_info *info, struct fb_info_control *p) { /* Fill fb_info */ - strcpy(info->modename, "control"); - info->currcon = -1; info->par = &p->par; info->node = NODEV; info->fbops = &controlfb_ops; - info->disp = &p->display; info->pseudo_palette = p->pseudo_palette; info->flags = FBINFO_FLAG_DEFAULT; - strncpy (info->fontname, fontname, sizeof (info->fontname)); - info->fontname[sizeof (info->fontname) - 1] = 0; - info->changevar = NULL; - info->display_fg = NULL; info->screen_base = (char *) p->frame_buffer + CTRLFB_OFF; - info->changevar = NULL; - info->switch_con = gen_switch; - info->updatevar = gen_update_var; fb_alloc_cmap(&info->cmap, 256, 0); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 27dc6417cddd..4d677aacb0e4 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -41,6 +41,9 @@ #include <asm/pgtable.h> #include <linux/fb.h> +#define INCLUDE_LINUX_LOGO_DATA +#include <asm/linux_logo.h> + #ifdef CONFIG_FRAMEBUFFER_CONSOLE #include "console/fbcon.h" #endif @@ -141,6 +144,8 @@ extern int pvr2fb_init(void); extern int pvr2fb_setup(char*); extern int sstfb_init(void); extern int sstfb_setup(char*); +extern int i810fb_init(void); +extern int i810fb_setup(char*); static struct { const char *name; @@ -155,11 +160,9 @@ static struct { */ { "sbus", sbusfb_init, sbusfb_setup }, #endif - /* * Chipset specific drivers that use resource management */ - #ifdef CONFIG_FB_RETINAZ3 { "retz3", retz3fb_init, retz3fb_setup }, #endif @@ -235,6 +238,12 @@ static struct { #ifdef CONFIG_FB_TRIDENT { "trident", tridentfb_init, tridentfb_setup }, #endif +#ifdef CONFIG_FB_I810 + { "i810fb", i810fb_init, i810fb_setup }, +#endif +#ifdef CONFIG_FB_STI + { "stifb", stifb_init, stifb_setup }, +#endif /* * Generic drivers that are used as fallbacks @@ -328,9 +337,6 @@ static struct { #ifdef CONFIG_FB_VGA16 { "vga16", vga16fb_init, vga16fb_setup }, #endif -#ifdef CONFIG_FB_STI - { "stifb", stifb_init, stifb_setup }, -#endif #ifdef CONFIG_GSP_RESOLVER /* Not a real frame buffer device... */ @@ -352,15 +358,264 @@ extern const char *global_mode_option; static initcall_t pref_init_funcs[FB_MAX]; static int num_pref_init_funcs __initdata = 0; - - struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; +static int nologo; #ifdef CONFIG_FB_OF static int ofonly __initdata = 0; #endif +#define LOGO_H 80 +#define LOGO_W 80 + +static inline unsigned safe_shift(unsigned d, int n) +{ + return n < 0 ? d >> -n : d << n; +} + +static void __init fb_set_logocmap(struct fb_info *info) +{ + struct fb_cmap palette_cmap; + u16 palette_green[16]; + u16 palette_blue[16]; + u16 palette_red[16]; + int i, j, n; + + palette_cmap.start = 0; + palette_cmap.len = 16; + palette_cmap.red = palette_red; + palette_cmap.green = palette_green; + palette_cmap.blue = palette_blue; + + for (i = 0; i < LINUX_LOGO_COLORS; i += n) { + n = LINUX_LOGO_COLORS - i; + /* palette_cmap provides space for only 16 colors at once */ + if (n > 16) + n = 16; + palette_cmap.start = 32 + i; + palette_cmap.len = n; + for (j = 0; j < n; ++j) { + palette_cmap.red[j] = + (linux_logo_red[i + j] << 8) | + linux_logo_red[i + j]; + palette_cmap.green[j] = + (linux_logo_green[i + j] << 8) | + linux_logo_green[i + j]; + palette_cmap.blue[j] = + (linux_logo_blue[i + j] << 8) | + linux_logo_blue[i + j]; + } + fb_set_cmap(&palette_cmap, 1, info); + } +} + +static void __init fb_set_logo_truepalette(struct fb_info *info, u32 *palette) +{ + unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; + unsigned char redmask, greenmask, bluemask; + int redshift, greenshift, blueshift; + int i; + + /* + * We have to create a temporary palette since console palette is only + * 16 colors long. + */ + /* Bug: Doesn't obey msb_right ... (who needs that?) */ + redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; + greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; + bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; + redshift = info->var.red.offset - (8 - info->var.red.length); + greenshift = info->var.green.offset - (8 - info->var.green.length); + blueshift = info->var.blue.offset - (8 - info->var.blue.length); + + for ( i = 0; i < LINUX_LOGO_COLORS; i++) { + palette[i+32] = (safe_shift((linux_logo_red[i] & redmask), redshift) | + safe_shift((linux_logo_green[i] & greenmask), greenshift) | + safe_shift((linux_logo_blue[i] & bluemask), blueshift)); + } +} + +static void __init fb_set_logo_directpalette(struct fb_info *info, u32 *palette) +{ + int redshift, greenshift, blueshift; + int i; + + redshift = info->var.red.offset; + greenshift = info->var.green.offset; + blueshift = info->var.blue.offset; + + for (i = 32; i < LINUX_LOGO_COLORS; i++) + palette[i] = i << redshift | i << greenshift | i << blueshift; +} + +static void __init fb_set_logo(struct fb_info *info, u8 *logo, int needs_logo) +{ + int i, j; + + switch (needs_logo) { + case 4: + for (i = 0; i < (LOGO_W * LOGO_H)/2; i++) { + logo[i*2] = linux_logo16[i] >> 4; + logo[(i*2)+1] = linux_logo16[i] & 0xf; + } + break; + case 1: + case ~1: + default: + for (i = 0; i < (LOGO_W * LOGO_H)/8; i++) + for (j = 0; j < 8; j++) + logo[i*8 + j] = (linux_logo_bw[i] & (7 - j)) ? + ((needs_logo == 1) ? 1 : 0) : + ((needs_logo == 1) ? 0 : 1); + break; + } +} + +/* + * Three (3) kinds of logo maps exist. linux_logo (>16 colors), linux_logo_16 + * (16 colors) and linux_logo_bw (2 colors). Depending on the visual format and + * color depth of the framebuffer, the DAC, the pseudo_palette, and the logo data + * will be adjusted accordingly. + * + * Case 1 - linux_logo: + * Color exceeds the number of console colors (16), thus we set the hardware DAC + * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. + * + * For visuals that require color info from the pseudo_palette, we also construct + * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags + * will be set. + * + * Case 2 - linux_logo_16: + * The number of colors just matches the console colors, thus there is no need + * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, + * each byte contains color information for two pixels (upper and lower nibble). + * To be consistent with fb_imageblit() usage, we therefore separate the two + * nibbles into separate bytes. The "needs_logo" flag will be set to 4. + * + * Case 3 - linux_logo_bw: + * This is similar with Case 2. Each byte contains information for 8 pixels. + * We isolate each bit and expand each into a byte. The "needs_logo" flag will + * be set to 1. + */ +int fb_show_logo(struct fb_info *info) +{ + unsigned char *fb = info->screen_base, *logo_new = NULL; + u32 *palette = NULL, *saved_palette = NULL; + int needs_directpalette = 0; + int needs_truepalette = 0; + int needs_cmapreset = 0; + struct fb_image image; + int needs_logo = 0; + int done = 0, x; + + /* Return if the frame buffer is not mapped */ + if (!fb || !info->fbops->fb_imageblit) + return 0; + + image.depth = info->var.bits_per_pixel; + + /* reasonable default */ + if (image.depth >= 8) + image.data = linux_logo; + else if (image.depth >= 4) + image.data = linux_logo16; + else + image.data = linux_logo_bw; + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + needs_truepalette = 1; + if (image.depth >= 4 && image.depth <= 8) + needs_logo = 4; + else if (image.depth < 4) + needs_logo = 1; + break; + case FB_VISUAL_DIRECTCOLOR: + if (image.depth >= 24) { + needs_directpalette = 1; + needs_cmapreset = 1; + } + /* 16 colors */ + else if (image.depth >= 16) + needs_logo = 4; + /* 2 colors */ + else + needs_logo = 1; + break; + case FB_VISUAL_MONO01: + /* reversed 0 = fg, 1 = bg */ + needs_logo = ~1; + break; + case FB_VISUAL_MONO10: + needs_logo = 1; + break; + case FB_VISUAL_PSEUDOCOLOR: + default: + if (image.depth >= 8) + needs_cmapreset = 1; + /* fall through */ + case FB_VISUAL_STATIC_PSEUDOCOLOR: + /* 16 colors */ + if (image.depth >= 4 && image.depth < 8) + needs_logo = 4; + /* 2 colors */ + else if (image.depth < 4) + needs_logo = 1; + break; + } + + if (needs_cmapreset) + fb_set_logocmap(info); + + if (needs_truepalette || needs_directpalette) { + palette = kmalloc(256 * 4, GFP_KERNEL); + if (palette == NULL) + return 1; + + if (needs_truepalette) + fb_set_logo_truepalette(info, palette); + else + fb_set_logo_directpalette(info, palette); + + saved_palette = info->pseudo_palette; + info->pseudo_palette = palette; + } + + if (needs_logo) { + logo_new = kmalloc(LOGO_W * LOGO_H, GFP_KERNEL); + if (logo_new == NULL) { + if (palette) + kfree(palette); + if (saved_palette) + info->pseudo_palette = saved_palette; + return 1; + } + + image.data = logo_new; + fb_set_logo(info, logo_new, needs_logo); + } + + image.width = LOGO_W; + image.height = LOGO_H; + image.dy = 0; + + for (x = 0; x < num_online_cpus() * (LOGO_W + 8) && + x < info->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) { + image.dx = x; + info->fbops->fb_imageblit(info, &image); + done = 1; + } + + if (palette != NULL) + kfree(palette); + if (saved_palette != NULL) + info->pseudo_palette = saved_palette; + if (logo_new != NULL) + kfree(logo_new); + return 0; +} + static int fbmem_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) { @@ -460,22 +715,19 @@ static void try_to_load(int fb) } #endif /* CONFIG_KMOD */ -int fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +int +fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { int xoffset = var->xoffset; int yoffset = var->yoffset; int err; - if (xoffset < 0 || yoffset < 0 || + if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display || xoffset + info->var.xres > info->var.xres_virtual || yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; - if (info->fbops->fb_pan_display) { - if ((err = info->fbops->fb_pan_display(var, info))) - return err; - else - return -EINVAL; - } + if ((err = info->fbops->fb_pan_display(var, info))) + return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -485,7 +737,8 @@ int fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -int fb_set_var(struct fb_var_screeninfo *var, struct fb_info *info) +int +fb_set_var(struct fb_var_screeninfo *var, struct fb_info *info) { int err; @@ -571,6 +824,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (copy_from_user(&cmap, (void *) arg, sizeof(cmap))) return -EFAULT; fb_copy_cmap(&info->cmap, &cmap, 0); + return 0; case FBIOPAN_DISPLAY: if (copy_from_user(&var, (void *) arg, sizeof(var))) return -EFAULT; @@ -704,6 +958,8 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #elif defined(__sh__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; +#elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #elif defined(__ia64__) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #else @@ -737,6 +993,8 @@ fb_open(struct inode *inode, struct file *file) if (res) module_put(info->fbops->owner); } + if (!nologo) + fb_show_logo(info); return res; } @@ -878,46 +1136,49 @@ fbmem_init(void) int __init video_setup(char *options) { - int i, j; + int i, j; - if (!options || !*options) - return 0; + if (!options || !*options) + return 0; #ifdef CONFIG_FB_OF - if (!strcmp(options, "ofonly")) { - ofonly = 1; - return 0; - } + if (!strcmp(options, "ofonly")) { + ofonly = 1; + return 0; + } #endif - if (num_pref_init_funcs == FB_MAX) - return 0; + if (!strcmp(options, "nologo")) + nologo = 1; - for (i = 0; i < NUM_FB_DRIVERS; i++) { - j = strlen(fb_drivers[i].name); - if (!strncmp(options, fb_drivers[i].name, j) && - options[j] == ':') { - if (!strcmp(options+j+1, "off")) - fb_drivers[i].init = NULL; - else { - if (fb_drivers[i].init) { - pref_init_funcs[num_pref_init_funcs++] = - fb_drivers[i].init; - fb_drivers[i].init = NULL; - } - if (fb_drivers[i].setup) - fb_drivers[i].setup(options+j+1); - } - return 0; - } - } + if (num_pref_init_funcs == FB_MAX) + return 0; - /* - * If we get here no fb was specified. - * We consider the argument to be a global video mode option. - */ - global_mode_option = options; - return 0; + for (i = 0; i < NUM_FB_DRIVERS; i++) { + j = strlen(fb_drivers[i].name); + if (!strncmp(options, fb_drivers[i].name, j) && + options[j] == ':') { + if (!strcmp(options+j+1, "off")) + fb_drivers[i].init = NULL; + else { + if (fb_drivers[i].init) { + pref_init_funcs[num_pref_init_funcs++] = + fb_drivers[i].init; + fb_drivers[i].init = NULL; + } + if (fb_drivers[i].setup) + fb_drivers[i].setup(options+j+1); + } + return 0; + } + } + + /* + * If we get here no fb was specified. + * We consider the argument to be a global video mode option. + */ + global_mode_option = options; + return 0; } __setup("video=", video_setup); @@ -928,7 +1189,10 @@ __setup("video=", video_setup); EXPORT_SYMBOL(register_framebuffer); EXPORT_SYMBOL(unregister_framebuffer); -EXPORT_SYMBOL(registered_fb); EXPORT_SYMBOL(num_registered_fb); +EXPORT_SYMBOL(registered_fb); +EXPORT_SYMBOL(fb_show_logo); +EXPORT_SYMBOL(fb_set_var); +EXPORT_SYMBOL(fb_blank); MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 77a796109a99..c7b2077180c4 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -1,77 +1,295 @@ /* * linux/drivers/video/fbmon.c * - * Copyright (C) 1999 James Simmons + * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. * - * Notes: - * This code handles the different types of monitors that are out their. - * Most video cards for example can support a mode like 800x600 but fix - * frequency monitors can't. So the code here checks if the monitor can - * support the mode as well as the card can. Fbmonospecs takes on - * different meaning with different types of monitors. For multifrequency - * monitors fbmonospecs represents the range of frequencies the monitor - * can support. Only one fbmonospec needs to be allocated. The fbmonospecs - * pointer in fb_info points to this one. If you specific a mode that has - * timing greater than the allowed range then setting the video mode will - * fail. With multifrequency monitors you can set any mode you like as long - * as you have a programmable clock on the video card. - * With fixed frequency monitors you have only a SET of very narrow - * allowed frequency ranges. So for a fixed fequency monitor you have a - * array of fbmonospecs. The fbmonospecs in fb_info represents the - * monitor frequency for the CURRENT mode. If you change the mode and ask - * for fbmonospecs you will NOT get the same values as before. Note this - * is not true for multifrequency monitors where you do get the same - * fbmonospecs each time. Also the values in each fbmonospecs represent the - * very narrow frequency band for range. Well you can't have exactly the - * same frequencies from fixed monitor. So some tolerance is excepted. - * By DEFAULT all monitors are assumed fixed frequency since they are so - * easy to fry or screw up a mode with. Just try setting a 800x600 mode on - * one. After you boot you can run a simple program the tells what kind of - * monitor you have. If you have a multifrequency monitor then you can set - * any mode size you like as long as your video card has a programmable clock. - * By default also besides assuming you have a fixed frequency monitor it - * assumes the monitor only supports lower modes. This way for example you - * can't set a 1280x1024 mode on a fixed frequency monitor that can only - * support up to 1024x768. - * */ #include <linux/tty.h> #include <linux/fb.h> #include <linux/module.h> +#ifdef CONFIG_PCI +#include <linux/pci.h> +#endif + +/* + * EDID parser + * + * portions of this file were based on the EDID parser by + * John Fremlin <vii@users.sourceforge.net> and Ani Joshi <ajoshi@unixbox.com> + */ + +#define EDID_LENGTH 0x80 +#define EDID_HEADER 0x00 +#define EDID_HEADER_END 0x07 + +#define ID_MANUFACTURER_NAME 0x08 +#define ID_MANUFACTURER_NAME_END 0x09 +#define ID_MODEL 0x0a + +#define ID_SERIAL_NUMBER 0x0c + +#define MANUFACTURE_WEEK 0x10 +#define MANUFACTURE_YEAR 0x11 + +#define EDID_STRUCT_VERSION 0x12 +#define EDID_STRUCT_REVISION 0x13 + +#define DPMS_FLAGS 0x18 +#define ESTABLISHED_TIMING_1 0x23 +#define ESTABLISHED_TIMING_2 0x24 +#define MANUFACTURERS_TIMINGS 0x25 + +#define DETAILED_TIMING_DESCRIPTIONS_START 0x36 +#define DETAILED_TIMING_DESCRIPTION_SIZE 18 +#define NO_DETAILED_TIMING_DESCRIPTIONS 4 + +#define DETAILED_TIMING_DESCRIPTION_1 0x36 +#define DETAILED_TIMING_DESCRIPTION_2 0x48 +#define DETAILED_TIMING_DESCRIPTION_3 0x5a +#define DETAILED_TIMING_DESCRIPTION_4 0x6c + +#define DESCRIPTOR_DATA 5 + +#define UPPER_NIBBLE( x ) \ + (((128|64|32|16) & (x)) >> 4) + +#define LOWER_NIBBLE( x ) \ + ((1|2|4|8) & (x)) + +#define COMBINE_HI_8LO( hi, lo ) \ + ( (((unsigned)hi) << 8) | (unsigned)lo ) + +#define COMBINE_HI_4LO( hi, lo ) \ + ( (((unsigned)hi) << 4) | (unsigned)lo ) + +#define PIXEL_CLOCK_LO (unsigned)block[ 0 ] +#define PIXEL_CLOCK_HI (unsigned)block[ 1 ] +#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*1000) +#define H_ACTIVE_LO (unsigned)block[ 2 ] +#define H_BLANKING_LO (unsigned)block[ 3 ] +#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO ) +#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO ) -int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, - const struct fb_info *fb_info) +#define V_ACTIVE_LO (unsigned)block[ 5 ] +#define V_BLANKING_LO (unsigned)block[ 6 ] +#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO ) +#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO ) + +#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ] +#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ] + +#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] ) +#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] ) + +#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2)) +#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2) + +#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4) +#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6) + +#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) +#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) + +#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) +#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) + +#define H_SIZE_LO (unsigned)block[ 12 ] +#define V_SIZE_LO (unsigned)block[ 13 ] + +#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] ) +#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] ) + +#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO ) +#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO ) + +#define H_BORDER (unsigned)block[ 15 ] +#define V_BORDER (unsigned)block[ 16 ] + +#define FLAGS (unsigned)block[ 17 ] + +#define INTERLACED (FLAGS&128) +#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */ +#define SYNC_SEPARATE (3<<3) +#define HSYNC_POSITIVE (FLAGS & 4) +#define VSYNC_POSITIVE (FLAGS & 2) + +const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00 +}; +const unsigned char edid_v1_descriptor_flag[] = { 0x00, 0x00 }; + +static int edid_checksum(unsigned char *edid) { -#if 0 - /* - * long long divisions .... $#%%#$ - */ - unsigned long long hpicos, vpicos; - const unsigned long long _1e12 = 1000000000000ULL; - const struct fb_monspecs *monspecs = &fb_info->monspecs; - - hpicos = (unsigned long long)htotal*(unsigned long long)pixclock; - vpicos = (unsigned long long)vtotal*(unsigned long long)hpicos; - if (!vpicos) - return 0; - - if (monspecs->hfmin == 0) - return 1; - - if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 || - vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12) - return 0; -#endif - return 1; + unsigned char i, csum = 0; + + for (i = 0; i < EDID_LENGTH; i++) + csum += edid[i]; + + if (csum == 0x00) { + /* checksum passed, everything's good */ + return 1; + } else { + printk("EDID checksum failed, aborting\n"); + return 0; + } } -int fbmon_dpms(const struct fb_info *fb_info) +static int edid_check_header(unsigned char *edid) { - return fb_info->monspecs.dpms; + if ((edid[0] != 0x00) || (edid[1] != 0xff) || (edid[2] != 0xff) || + (edid[3] != 0xff) || (edid[4] != 0xff) || (edid[5] != 0xff) || + (edid[6] != 0xff)) { + printk + ("EDID header doesn't match EDID v1 header, aborting\n"); + return 0; + } + return 1; } -EXPORT_SYMBOL(fbmon_valid_timings); + +static char *edid_get_vendor(unsigned char *block) +{ + static char sign[4]; + unsigned short h; + + h = COMBINE_HI_8LO(block[0], block[1]); + sign[0] = ((h >> 10) & 0x1f) + 'A' - 1; + sign[1] = ((h >> 5) & 0x1f) + 'A' - 1; + sign[2] = (h & 0x1f) + 'A' - 1; + sign[3] = 0; + + return sign; +} + +static char *edid_get_monitor(unsigned char *block) +{ + static char name[13]; + unsigned i; + const unsigned char *ptr = block + DESCRIPTOR_DATA; + + for (i = 0; i < 13; i++, ptr++) { + if (*ptr == 0xa) { + name[i] = 0x00; + return name; + } + name[i] = *ptr; + } + return name; +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00)) + return 0; + else + return 1; +} + +static int edid_is_monitor_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && (block[3] == 0xfc)) + return 1; + else + return 0; +} + +static void parse_timing_block(unsigned char *block, + struct fb_var_screeninfo *var) +{ + var->xres = var->xres_virtual = H_ACTIVE; + var->yres = var->yres_virtual = V_ACTIVE; + var->height = var->width = -1; + var->right_margin = H_SYNC_OFFSET; + var->left_margin = (H_ACTIVE + H_BLANKING) - + (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); + var->upper_margin = V_BLANKING - V_SYNC_OFFSET - V_SYNC_WIDTH; + var->lower_margin = V_SYNC_OFFSET; + var->hsync_len = H_SYNC_WIDTH; + var->vsync_len = V_SYNC_WIDTH; + var->pixclock = PIXEL_CLOCK; + var->pixclock /= 1000; + var->pixclock = KHZ2PICOS(var->pixclock); + + if (HSYNC_POSITIVE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (VSYNC_POSITIVE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) +{ + unsigned char *block, *vendor, *monitor = NULL; + int i; + + if (!(edid_checksum(edid))) + return 0; + + if (!(edid_check_header(edid))) + return 0; + + printk("EDID ver %d rev %d\n", (int) edid[EDID_STRUCT_VERSION], + (int) edid[EDID_STRUCT_REVISION]); + + vendor = edid_get_vendor(edid + ID_MANUFACTURER_NAME); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_monitor_block(block)) { + monitor = edid_get_monitor(block); + } + } + + printk("EDID: detected %s %s\n", vendor, monitor); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_timing_block(block)) { + parse_timing_block(block, var); + } + } + return 1; +} + +#ifdef CONFIG_PCI +char *get_EDID(struct pci_dev *pdev) +{ +#ifdef CONFIG_ALL_PPC + static char *propnames[] = + { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL }; + unsigned char *pedid = NULL; + struct device_node *dp; + int i; + + dp = pci_device_to_OF_node(pdev); + while (dp != NULL) { + for (i = 0; propnames[i] != NULL; ++i) { + pedid = + (unsigned char *) get_property(dp, + propnames[i], + NULL); + if (pedid != NULL) + return pedid; + } + dp = dp->child; + } + return pedid; +#else + return NULL; +#endif +} +#endif + +EXPORT_SYMBOL(parse_edid); +#ifdef CONFIG_PCI +EXPORT_SYMBOL(get_EDID); +#endif diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile new file mode 100644 index 000000000000..2cdcc59b3cff --- /dev/null +++ b/drivers/video/i810/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the Intel 810/815 framebuffer driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + + +obj-$(CONFIG_FB_I810) += i810fb.o + + +i810fb-objs := i810_main.o i810_accel.o + +ifdef CONFIG_FB_I810_GTF +i810fb-objs += i810_gtf.o +else +i810fb-objs += i810_dvt.o +endif + +include $(TOPDIR)/Rules.make diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h new file mode 100644 index 000000000000..3a548d4fa5c6 --- /dev/null +++ b/drivers/video/i810/i810.h @@ -0,0 +1,300 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810.h -- Intel 810 General Definitions/Declarations + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __I810_H__ +#define __I810_H__ + +#include <linux/list.h> +#include <linux/agp_backend.h> +#include <linux/fb.h> +#include <video/vga.h> + +/* Fence */ +#define TILEWALK_X (0 << 12) +#define TILEWALK_Y (1 << 12) + +/* Raster ops */ +#define COLOR_COPY_ROP 0xF0 +#define PAT_COPY_ROP 0xCC +#define CLEAR_ROP 0x00 +#define WHITE_ROP 0xFF +#define INVERT_ROP 0x55 +#define XOR_ROP 0x5A + +/* 2D Engine definitions */ +#define SOLIDPATTERN 0x80000000 +#define NONSOLID 0x00000000 +#define BPP8 (0 << 24) +#define BPP16 (1 << 24) +#define BPP24 (2 << 24) + +#define PIXCONF8 (2 << 16) +#define PIXCONF15 (4 << 16) +#define PIXCONF16 (5 << 16) +#define PIXCONF24 (6 << 16) +#define PIXCONF32 (7 << 16) + +#define DYN_COLOR_EN (1 << 26) +#define DYN_COLOR_DIS (0 << 26) +#define INCREMENT 0x00000000 +#define DECREMENT (0x01 << 30) +#define ARB_ON 0x00000001 +#define ARB_OFF 0x00000000 +#define SYNC_FLIP 0x00000000 +#define ASYNC_FLIP 0x00000040 +#define OPTYPE_MASK 0xE0000000 +#define PARSER_MASK 0x001F8000 +#define D2_MASK 0x001FC000 /* 2D mask */ + +/* Instruction type */ +/* There are more but pertains to 3D */ +#define PARSER 0x00000000 +#define BLIT (0x02 << 29) +#define RENDER (0x03 << 29) + +/* Parser */ +#define NOP 0x00 /* No operation, padding */ +#define BP_INT (0x01 << 23) /* Breakpoint interrupt */ +#define USR_INT (0x02 << 23) /* User interrupt */ +#define WAIT_FOR_EVNT (0x03 << 23) /* Wait for event */ +#define FLUSH (0x04 << 23) +#define CONTEXT_SEL (0x05 << 23) +#define REPORT_HEAD (0x07 << 23) +#define ARB_ON_OFF (0x08 << 23) +#define OVERLAY_FLIP (0x11 << 23) +#define LOAD_SCAN_INC (0x12 << 23) +#define LOAD_SCAN_EX (0x13 << 23) +#define FRONT_BUFFER (0x14 << 23) +#define DEST_BUFFER (0x15 << 23) +#define Z_BUFFER (0x16 << 23) + +#define STORE_DWORD_IMM (0x20 << 23) +#define STORE_DWORD_IDX (0x21 << 23) +#define BATCH_BUFFER (0x30 << 23) + +/* Blit */ +#define SETUP_BLIT 0x00 +#define SETUP_MONO_PATTERN_SL_BLT (0x10 << 22) +#define PIXEL_BLT (0x20 << 22) +#define SCANLINE_BLT (0x21 << 22) +#define TEXT_BLT (0x22 << 22) +#define TEXT_IMM_BLT (0x30 << 22) +#define COLOR_BLT (0x40 << 22) +#define MONO_PAT_BLIT (0x42 << 22) +#define SOURCE_COPY_BLIT (0x43 << 22) +#define MONO_SOURCE_COPY_BLIT (0x44 << 22) +#define SOURCE_COPY_IMMEDIATE (0x60 << 22) +#define MONO_SOURCE_COPY_IMMEDIATE (0x61 << 22) + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 9 +#define VERSION_TEENIE 0 +#define BRANCH_VERSION "" + + +/* mvo: intel i815 */ +#ifndef PCI_DEVICE_ID_INTEL_82815_100 + #define PCI_DEVICE_ID_INTEL_82815_100 0x1102 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82815_NOAGP + #define PCI_DEVICE_ID_INTEL_82815_NOAGP 0x1112 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82815_FULL_CTRL + #define PCI_DEVICE_ID_INTEL_82815_FULL_CTRL 0x1130 +#endif + +/* General Defines */ +#define I810_PAGESIZE 4096 +#define MAX_DMA_SIZE (1024 * 4096) +#define SAREA_SIZE 4096 +#define PCI_I810_MISCC 0x72 +#define MMIO_SIZE (512*1024) +#define GTT_SIZE (16*1024) +#define RINGBUFFER_SIZE (64*1024) +#define PIXMAP_SIZE (4 * 4096) +#define CURSOR_SIZE 4096 +#define OFF 0 +#define ON 1 +#define MAX_KEY 256 +#define WAIT_COUNT 10000000 +#define IRING_PAD 8 +#define FONTDATAMAX 8192 +/* Masks (AND ops) and OR's */ +#define FB_START_MASK (0x3f << (32 - 6)) +#define MMIO_ADDR_MASK (0x1FFF << (32 - 13)) +#define FREQ_MASK 0x1EF +#define SCR_OFF 0x20 +#define DRAM_ON 0x08 +#define DRAM_OFF 0xE7 +#define PG_ENABLE_MASK 0x01 +#define RING_SIZE_MASK (RINGBUFFER_SIZE - 1); + +/* defines for restoring registers partially */ +#define ADDR_MAP_MASK (0x07 << 5) +#define DISP_CTRL ~0 +#define PIXCONF_0 (0x64 << 8) +#define PIXCONF_2 (0xF3 << 24) +#define PIXCONF_1 (0xF0 << 16) +#define MN_MASK 0x3FF03FF +#define P_OR (0x7 << 4) +#define DAC_BIT (1 << 16) +#define INTERLACE_BIT (1 << 7) +#define IER_MASK (3 << 13) +#define IMR_MASK (3 << 13) + +/* Power Management */ +#define DPMS_MASK 0xF0000 +#define POWERON 0x00000 +#define STANDBY 0x20000 +#define SUSPEND 0x80000 +#define POWERDOWN 0xA0000 +#define EMR_MASK ~0x3F +#define FW_BLC_MASK ~(0x3F|(7 << 8)|(0x3F << 12)|(7 << 20)) + +/* Ringbuffer */ +#define RBUFFER_START_MASK 0xFFFFF000 +#define RBUFFER_SIZE_MASK 0x001FF000 +#define RBUFFER_HEAD_MASK 0x001FFFFC +#define RBUFFER_TAIL_MASK 0x001FFFF8 + +/* Video Timings */ +#define REF_FREQ 24000000 +#define TARGET_N_MAX 30 + +#define FLYBACK 550 +#define V_FRONTPORCH 1 +#define H_OFFSET 40 +#define H_SCALEFACTOR 20 +#define H_BLANKSCALE 128 +#define H_GRADIENT 600 + +#define MAX_PIXELCLOCK 230000000 +#define MIN_PIXELCLOCK 15000000 +#define VFMAX 60 +#define VFMIN 60 +#define HFMAX 30000 +#define HFMIN 29000 + +/* Cursor */ +#define CURSOR_ENABLE_MASK 0x1000 +#define CURSOR_MODE_64_TRANS 4 +#define CURSOR_MODE_64_XOR 5 +#define CURSOR_MODE_64_3C 6 +#define COORD_INACTIVE 0 +#define COORD_ACTIVE (1 << 4) +#define EXTENDED_PALETTE 1 + +/* AGP Memory Types*/ +#define AGP_NORMAL_MEMORY 0 +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYSICAL_MEMORY 2 + +/* Allocated resource Flags */ +#define FRAMEBUFFER_REQ 1 +#define MMIO_REQ 2 +#define PCI_DEVICE_ENABLED 4 +#define HAS_FONTCACHE 8 + +/* driver flags */ +#define HAS_MTRR 1 +#define HAS_ACCELERATION 2 +#define ALWAYS_SYNC 4 +#define LOCKUP 8 + +struct gtt_data { + agp_memory *i810_fb_memory; + agp_memory *i810_iring_memory; + agp_memory *i810_cursor_memory; + agp_memory *i810_pixmap_memory; +}; + +struct mode_registers { + u32 pixclock, M, N, P; + u8 cr00, cr01, cr02, cr03; + u8 cr04, cr05, cr06, cr07; + u8 cr09, cr10, cr11, cr12; + u8 cr13, cr15, cr16, cr30; + u8 cr31, cr32, cr33, cr35, cr39; + u32 bpp8_100, bpp16_100; + u32 bpp24_100, bpp8_133; + u32 bpp16_133, bpp24_133; + u8 msr; +}; + +struct heap_data { + unsigned long physical; + __u8 *virtual; + u32 offset; + u32 size; +}; + +struct state_registers { + u32 dclk_1d, dclk_2d, dclk_0ds; + u32 pixconf, fw_blc, pgtbl_ctl; + u32 fence0, hws_pga, dplystas; + u16 bltcntl, hwstam, ier, iir, imr; + u8 cr00, cr01, cr02, cr03, cr04; + u8 cr05, cr06, cr07, cr08, cr09; + u8 cr10, cr11, cr12, cr13, cr14; + u8 cr15, cr16, cr17, cr80, gr10; + u8 cr30, cr31, cr32, cr33, cr35; + u8 cr39, cr41, cr70, sr01, msr; +}; + +struct i810fb_par { + struct mode_registers regs; + struct state_registers hw_state; + struct gtt_data i810_gtt; + struct fb_ops i810fb_ops; + struct pci_dev *dev; + struct heap_data aperture; + struct heap_data fb; + struct heap_data iring; + struct heap_data cursor_heap; + struct heap_data pixmap; + struct vgastate state; + drm_agp_t *drm_agp; + atomic_t use_count; + u32 pseudo_palette[17]; + unsigned long mmio_start_phys; + u8 *mmio_start_virtual; + u32 cursor_reset; + u8 red[64]; + u8 green[64]; + u8 blue[64]; + u32 pixmap_offset; + u32 pitch; + u32 pixconf; + u32 watermark; + u32 mem_freq; + u32 res_flags; + u32 dev_flags; + u32 cur_tail; + u32 depth; + u32 blit_bpp; + u32 ovract; + int mtrr_reg; + u16 bltcntl; + u8 interlace; +}; + +/* + * Register I/O + */ +#define i810_readb(where, mmio) readb(mmio + where) +#define i810_readw(where, mmio) readw(mmio + where) +#define i810_readl(where, mmio) readl(mmio + where) +#define i810_writeb(where, mmio, val) writeb(val, mmio + where) +#define i810_writew(where, mmio, val) writew(val, mmio + where) +#define i810_writel(where, mmio, val) writel(val, mmio + where) + +#endif /* __I810_H__ */ diff --git a/drivers/video/i810/i810_accel.c b/drivers/video/i810/i810_accel.c new file mode 100644 index 000000000000..95fb0600b9e1 --- /dev/null +++ b/drivers/video/i810/i810_accel.c @@ -0,0 +1,513 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_accel.c -- Hardware Acceleration + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/kernel.h> +#include <linux/fb.h> + +#include "i810_regs.h" +#include "i810.h" + +static u32 i810fb_rop[] = { + COLOR_COPY_ROP, /* ROP_COPY */ + XOR_ROP /* ROP_XOR */ +}; + +/* Macros */ +#define PUT_RING(n) { \ + i810_writel(par->cur_tail, par->iring.virtual, n); \ + par->cur_tail += 4; \ + par->cur_tail &= RING_SIZE_MASK; \ +} + +extern inline void flush_cache(void); +extern int reinit_agp(struct fb_info *info); + +/************************************************************/ + +/* BLT Engine Routines */ +static inline void i810_report_error(u8 *mmio) +{ + printk("IIR : 0x%04x\n" + "EIR : 0x%04x\n" + "PGTBL_ER: 0x%04x\n" + "IPEIR : 0x%04x\n" + "IPEHR : 0x%04x\n", + i810_readw(IIR, mmio), + i810_readb(EIR, mmio), + i810_readl(PGTBL_ER, mmio), + i810_readl(IPEIR, mmio), + i810_readl(IPEHR, mmio)); +} + +/** + * wait_for_space - check ring buffer free space + * @space: amount of ringbuffer space needed in bytes + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * The function waits until a free space from the ringbuffer + * is available + */ +static inline int wait_for_space(struct i810fb_par *par, u32 space) +{ + u32 head, count = WAIT_COUNT, tail; + u8 *mmio = par->mmio_start_virtual; + + tail = par->cur_tail; + while (count--) { + head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK; + if ((tail == head) || + (tail > head && + (par->iring.size - tail + head) >= space) || + (tail < head && (head - tail) >= space)) { + return 0; + } + } + printk("ringbuffer lockup!!!\n"); + i810_report_error(mmio); + par->dev_flags |= LOCKUP; + return 1; +} + + + +/** + * wait_for_engine_idle - waits for all hardware engines to finish + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This waits for lring(0), iring(1), and batch(3), etc to finish and + * waits until ringbuffer is empty. + */ +static inline int wait_for_engine_idle(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + int count = WAIT_COUNT; + + while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count); + if (count) return 0; + + printk("accel engine lockup!!!\n"); + printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio)); + i810_report_error(mmio); + par->dev_flags |= LOCKUP; + return 1; +} + +/* begin_iring - prepares the ringbuffer + * @space: length of sequence in dwords + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Checks/waits for sufficent space in ringbuffer of size + * space. Returns the tail of the buffer + */ +static inline u32 begin_iring(struct i810fb_par *par, u32 space) +{ + if (par->dev_flags & ALWAYS_SYNC) + wait_for_engine_idle(par); + return wait_for_space(par, space); +} + +/** + * end_iring - advances the buffer + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This advances the tail of the ringbuffer, effectively + * beginning the execution of the graphics instruction sequence. + */ +static inline void end_iring(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + i810_writel(IRING, mmio, par->cur_tail); +} + +/** + * source_copy_blit - BLIT transfer operation + * @dwidth: width of rectangular graphics data + * @dheight: height of rectangular graphics data + * @dpitch: bytes per line of destination buffer + * @xdir: direction of copy (left to right or right to left) + * @src: address of first pixel to read from + * @dest: address of first pixel to write to + * @from: source address + * @where: destination address + * @rop: raster operation + * @blit_bpp: pixel format which can be different from the + * framebuffer's pixelformat + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This is a BLIT operation typically used when doing + * a 'Copy and Paste' + */ +static inline void source_copy_blit(int dwidth, int dheight, int dpitch, + int xdir, int src, int dest, int rop, + int blit_bpp, struct i810fb_par *par) +{ + if (begin_iring(par, 24 + IRING_PAD)) return; + PUT_RING(BLIT | SOURCE_COPY_BLIT | 4); + PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp); + PUT_RING(dheight << 16 | dwidth); + PUT_RING(dest); + PUT_RING(dpitch); + PUT_RING(src); + end_iring(par); +} + +/** + * color_blit - solid color BLIT operation + * @width: width of destination + * @height: height of destination + * @pitch: pixels per line of the buffer + * @dest: address of first pixel to write to + * @where: destination + * @rop: raster operation + * @what: color to transfer + * @blit_bpp: pixel format which can be different from the + * framebuffer's pixelformat + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * A BLIT operation which can be used for color fill/rectangular fill + */ +static inline void color_blit(int width, int height, int pitch, int dest, + int rop, int what, int blit_bpp, + struct i810fb_par *par) +{ + if (begin_iring(par, 24 + IRING_PAD)) return; + PUT_RING(BLIT | COLOR_BLT | 3); + PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp); + PUT_RING(height << 16 | width); + PUT_RING(dest); + PUT_RING(what); + PUT_RING(NOP); + end_iring(par); +} + +/** + * mono_src_copy_imm_blit - color expand from system memory to framebuffer + * @dwidth: width of destination + * @dheight: height of destination + * @dpitch: pixels per line of the buffer + * @dsize: size of bitmap in double words + * @dest: address of first byte of pixel; + * @rop: raster operation + * @blit_bpp: pixelformat to use which can be different from the + * framebuffer's pixelformat + * @src: address of image data + * @bg: backgound color + * @fg: forground color + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * A color expand operation where the source data is placed in the + * ringbuffer itself. Useful for drawing text. + * + * REQUIREMENT: + * The end of a scanline must be padded to the next word. + */ +static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch, + int dsize, int blit_bpp, int rop, + int dest, const u32 *src, int bg, + int fg, struct i810fb_par *par) +{ + u32 i, *s = (u32 *) src; + + if (begin_iring(par, 24 + (dsize << 2) + IRING_PAD)) return; + PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize)); + PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch); + PUT_RING(dheight << 16 | dwidth); + PUT_RING(dest); + PUT_RING(bg); + PUT_RING(fg); + for (i = dsize; i--; ) + PUT_RING(*s++); + + end_iring(par); +} + +/** + * mono_src_copy_blit - color expand from video memory to framebuffer + * @dwidth: width of destination + * @dheight: height of destination + * @dpitch: pixels per line of the buffer + * @qsize: size of bitmap in quad words + * @dest: address of first byte of pixel; + * @rop: raster operation + * @blit_bpp: pixelformat to use which can be different from the + * framebuffer's pixelformat + * @src: address of image data + * @bg: backgound color + * @fg: forground color + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * A color expand operation where the source data is in video memory. + * Useful for drawing text. + * + * REQUIREMENT: + * The end of a scanline must be padded to the next word. + */ +static inline void mono_src_copy_blit(int dwidth, int dheight, int dpitch, + int qsize, int blit_bpp, int rop, + int dest, int src, int bg, + int fg, struct i810fb_par *par) +{ + if (begin_iring(par, 32 + IRING_PAD)) return; + + PUT_RING(BLIT | MONO_SOURCE_COPY_BLIT | 6); + PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch | 1 << 27); + PUT_RING(dheight << 16 | dwidth); + PUT_RING(dest); + PUT_RING(qsize - 1); + PUT_RING(src); + PUT_RING(bg); + PUT_RING(fg); + + end_iring(par); +} + +static u32 get_buffer_offset(u32 size, struct i810fb_par *par) +{ + u32 offset; + + if (par->pixmap_offset + size > par->pixmap.size) { + wait_for_engine_idle(par); + par->pixmap_offset = 0; + } + + offset = par->pixmap_offset; + par->pixmap_offset += size; + + return offset; +} + +/** + * i810fb_iring_enable - enables/disables the ringbuffer + * @mode: enable or disable + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Enables or disables the ringbuffer, effectively enabling or + * disabling the instruction/acceleration engine. + */ +static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode) +{ + u32 tmp; + u8 *mmio = par->mmio_start_virtual; + + tmp = i810_readl(IRING + 12, mmio); + if (mode == OFF) + tmp &= ~1; + else + tmp |= 1; + flush_cache(); + i810_writel(IRING + 12, mmio, tmp); +} + +void i810fb_fillrect(struct fb_info *p, struct fb_fillrect *rect) +{ + struct i810fb_par *par = (struct i810fb_par *) p->par; + u32 dx, dy, width, height, dest, rop = 0, color = 0; + + if (!p->var.accel_flags || par->dev_flags & LOCKUP) { + cfb_fillrect(p, rect); + return; + } + + if (par->depth == 4) { + wait_for_engine_idle(par); + cfb_fillrect(p, rect); + return; + } + + if (par->depth == 1) + color = rect->color; + else + color = ((u32 *) (p->pseudo_palette))[rect->color]; + + rop = i810fb_rop[rect->rop]; + + dx = rect->dx * par->depth; + width = rect->width * par->depth; + dy = rect->dy; + height = rect->height; + + dest = p->fix.smem_start + (dy * p->fix.line_length) + dx; + color_blit(width, height, p->fix.line_length, dest, rop, color, + par->blit_bpp, par); +} + +void i810fb_copyarea(struct fb_info *p, struct fb_copyarea *region) +{ + struct i810fb_par *par = (struct i810fb_par *) p->par; + u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir; + + if (!p->var.accel_flags || par->dev_flags & LOCKUP) { + cfb_copyarea(p, region); + return; + } + + if (par->depth == 4) { + wait_for_engine_idle(par); + cfb_copyarea(p, region); + return; + } + + dx = region->dx * par->depth; + sx = region->sx * par->depth; + width = region->width * par->depth; + sy = region->sy; + dy = region->dy; + height = region->height; + + if (dx <= sx) { + xdir = INCREMENT; + } + else { + xdir = DECREMENT; + sx += width - 1; + dx += width - 1; + } + if (dy <= sy) { + pitch = p->fix.line_length; + } + else { + pitch = (-(p->fix.line_length)) & 0xFFFF; + sy += height - 1; + dy += height - 1; + } + src = p->fix.smem_start + (sy * p->fix.line_length) + sx; + dest = p->fix.smem_start + (dy * p->fix.line_length) + dx; + + source_copy_blit(width, height, pitch, xdir, src, dest, + PAT_COPY_ROP, par->blit_bpp, par); +} + +/* + * Blitting is done at 8x8 pixel-array at a time. If map is not + * monochrome or not a multiple of 8x8 pixels, cfb_imageblit will + * be called instead. + */ +void i810fb_imageblit(struct fb_info *p, struct fb_image *image) +{ + struct i810fb_par *par = (struct i810fb_par *) p->par; + u32 fg = 0, bg = 0, s_pitch, d_pitch, size, offset, dst, i, j; + u8 *s_addr, *d_addr; + + if (!p->var.accel_flags || par->dev_flags & LOCKUP) { + cfb_imageblit(p, image); + return; + } + + if (par->depth == 4 || image->depth != 1) { + wait_for_engine_idle(par); + cfb_imageblit(p, image); + return; + } + + switch (p->var.bits_per_pixel) { + case 8: + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + fg = ((u32 *)(p->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(p->pseudo_palette))[image->bg_color]; + break; + case 24: + fg = ((u32 *)(p->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(p->pseudo_palette))[image->bg_color]; + break; + } + + dst = p->fix.smem_start + (image->dy * p->fix.line_length) + + (image->dx * par->depth); + + s_pitch = image->width/8; + d_pitch = (s_pitch + 1) & ~1; + + size = d_pitch * image->height; + + if (image->width & 15) { + offset = get_buffer_offset(size, par); + + d_addr = par->pixmap.virtual + offset; + s_addr = image->data; + + for (i = image->height; i--; ) { + for (j = 0; j < s_pitch; j++) + i810_writeb(j, d_addr, s_addr[j]); + s_addr += s_pitch; + d_addr += d_pitch; + } + + mono_src_copy_blit(image->width * par->depth, image->height, + p->fix.line_length, size/8, par->blit_bpp, + PAT_COPY_ROP, dst, + par->pixmap.physical + offset, + bg, fg, par); + } + /* + * immediate blit if width is a multiple of 16 (hardware requirement) + */ + else { + mono_src_copy_imm_blit(image->width * par->depth, + image->height, p->fix.line_length, + size/4, par->blit_bpp, + PAT_COPY_ROP, dst, (u32 *) image->data, + bg, fg, par); + } +} + +int i810fb_sync(struct fb_info *p) +{ + struct i810fb_par *par = (struct i810fb_par *) p->par; + + if (!p->var.accel_flags) + return 0; + + return wait_for_engine_idle(par); +} + + +/** + * i810fb_init_ringbuffer - initialize the ringbuffer + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Initializes the ringbuffer by telling the device the + * size and location of the ringbuffer. It also sets + * the head and tail pointers = 0 + */ +void i810fb_init_ringbuffer(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 *mmio = par->mmio_start_virtual; + + wait_for_engine_idle(par); + i810fb_iring_enable(par, OFF); + i810_writel(IRING, mmio, 0); + i810_writel(IRING + 4, mmio, 0); + par->cur_tail = 0; + + tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK; + tmp1 = par->iring.physical; + i810_writel(IRING + 8, mmio, tmp2 | tmp1); + + tmp1 = i810_readl(IRING + 12, mmio); + tmp1 &= ~RBUFFER_SIZE_MASK; + tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK; + i810_writel(IRING + 12, mmio, tmp1 | tmp2); + i810fb_iring_enable(par, ON); +} diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c new file mode 100644 index 000000000000..ad417bb698e8 --- /dev/null +++ b/drivers/video/i810/i810_dvt.c @@ -0,0 +1,308 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_dvt.c -- Intel 810 Discrete Video Timings (Intel) + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/kernel.h> + +#include "i810_regs.h" +#include "i810.h" + +struct mode_registers std_modes[] = { + /* 640x480 @ 60Hz */ + { 25000, 0x0013, 0x0003, 0x40, 0x5F, 0x4F, 0x50, 0x82, 0x51, 0x9D, + 0x0B, 0x10, 0x40, 0xE9, 0x0B, 0xDF, 0x50, 0xE7, 0x04, 0x02, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22006000, + 0x22002000, 0x22004000, 0x22006000, 0xC0 }, + + /* 640x480 @ 70Hz */ + { 28000, 0x0053, 0x0010, 0x40, 0x61, 0x4F, 0x4F, 0x85, 0x52, 0x9A, + 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22005000, + 0x22002000, 0x22004000, 0x22005000, 0xC0 }, + + /* 640x480 @ 72Hz */ + { 31000, 0x0013, 0x0002, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x52, 0x97, + 0x06, 0x0F, 0x40, 0xE8, 0x0B, 0xDF, 0x50, 0xDF, 0x07, 0x02, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000, + 0x22003000, 0x22005000, 0x22007000, 0xC0 }, + + /* 640x480 @ 75Hz */ + { 31000, 0x0013, 0x0002, 0x40, 0x64, 0x4F, 0x4F, 0x88, 0x51, 0x99, + 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000, + 0x22003000, 0x22005000, 0x22007000, 0xC0 }, + + /* 640x480 @ 85Hz */ + { 36000, 0x0010, 0x0001, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x56, 0x9D, + 0xFB, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xFC, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000, + 0x22003000, 0x22005000, 0x22107000, 0xC0 }, + + /* 800x600 @ 56Hz */ + { 36000, 0x0010, 0x0001, 0x40, 0x7B, 0x63, 0x63, 0x9F, 0x66, 0x8F, + 0x6F, 0x10, 0x40, 0x58, 0x0A, 0x57, 0xC8, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000, + 0x22003000, 0x22005000, 0x22107000, 0x00 }, + + /* 800x600 @ 60Hz */ + { 40000, 0x0008, 0x0001, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x68, 0x18, + 0x72, 0x10, 0x40, 0x58, 0x0C, 0x57, 0xC8, 0x57, 0x73, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22003000, 0x22006000, 0x22108000, + 0x22003000, 0x22006000, 0x22108000, 0x00 }, + + /* 800x600 @ 70Hz */ + { 45000, 0x0054, 0x0015, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x68, 0x12, + 0x6f, 0x10, 0x40, 0x58, 0x0b, 0x57, 0x64, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000, + 0x22004000, 0x22007000, 0x2210A000, 0x00 }, + + /* 800x600 @ 72Hz */ + { 50000, 0x0017, 0x0004, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x6A, 0x19, + 0x98, 0x10, 0x40, 0x7C, 0x02, 0x57, 0xC8, 0x57, 0x99, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000, + 0x22004000, 0x22007000, 0x2210A000, 0x00 }, + + /* 800x600 @ 75Hz */ + { 49000, 0x001F, 0x0006, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x65, 0x0F, + 0x6F, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210B000, + 0x22004000, 0x22007000, 0x2210B000, 0x00 }, + + /* 800x600 @ 85Hz */ + { 56000, 0x0049, 0x000E, 0x30, 0x7E, 0x63, 0x63, 0x82, 0x67, 0x0F, + 0x75, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x76, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22108000, 0x2210b000, + 0x22004000, 0x22108000, 0x2210b000, 0x00 }, + + /* 1024x768 @ 60Hz */ + { 65000, 0x003F, 0x000A, 0x30, 0xA3, 0x7F, 0x7F, 0x87, 0x83, 0x94, + 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x22109000, 0x2220D000, + 0x22005000, 0x22109000, 0x2220D000, 0xC0 }, + + /* 1024x768 @ 70Hz */ + { 75000, 0x0017, 0x0002, 0x30, 0xA1, 0x7F, 0x7F, 0x85, 0x82, 0x93, + 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x2210A000, 0x2220F000, + 0x22005000, 0x2210A000, 0x2220F000, 0xC0 }, + + /* 1024x768 @ 75Hz */ + { 78000, 0x0050, 0x0017, 0x20, 0x9F, 0x7F, 0x7F, 0x83, 0x81, 0x8D, + 0x1E, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x1F, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22006000, 0x2210B000, 0x22210000, + 0x22006000, 0x2210B000, 0x22210000, 0x00 }, + + /* 1024x768 @ 85Hz */ + { 94000, 0x003D, 0x000E, 0x20, 0xA7, 0x7F, 0x7F, 0x8B, 0x85, 0x91, + 0x26, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x27, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22007000, 0x2220E000, 0x22212000, + 0x22007000, 0x2220E000, 0x22212000, 0x00 }, + + /* 1152x864 @ 60Hz */ + { 80000, 0x0008, 0x0001, 0x20, 0xB3, 0x8F, 0x8F, 0x97, 0x93, 0x9f, + 0x87, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5f, 0x88, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x2220C000, 0x22210000, 0x22415000, + 0x2220C000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 70Hz */ + { 96000, 0x000a, 0x0001, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87, + 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 72Hz */ + { 99000, 0x001f, 0x0006, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87, + 0x83, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x84, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 75Hz */ + { 108000, 0x0010, 0x0002, 0x20, 0xC3, 0x8F, 0x8F, 0x87, 0x97, 0x07, + 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 85Hz */ + { 121000, 0x006D, 0x0014, 0x20, 0xc0, 0x8F, 0x8F, 0x84, 0x97, 0x07, + 0x93, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x94, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2220C000, 0x22210000, 0x22415000, + 0x2220C000, 0x22210000, 0x22415000, 0x0 }, + + /* 1280x960 @ 60Hz */ + { 108000, 0x0010, 0x0002, 0x20, 0xDC, 0x9F, 0x9F, 0x80, 0xAB, 0x99, + 0xE6, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE7, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x22415000, + 0x2210A000, 0x22210000, 0x22415000, 0x00 }, + + /* 1280x960 @ 75Hz */ + { 129000, 0x0029, 0x0006, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xaa, 0x1b, + 0xE8, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE9, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x2241B000, + 0x2210A000, 0x22210000, 0x2241B000, 0x00 }, + + /* 1280x960 @ 85Hz */ + { 148000, 0x0042, 0x0009, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xA7, 0x1B, + 0xF1, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xF2, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22220000, 0x2241D000, + 0x2210A000, 0x22220000, 0x2241D000, 0x00 }, + + /* 1600x1200 @ 60Hz */ + { 162000, 0x0019, 0x0006, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210b000, 0x22416000, 0x44419000, + 0x2210b000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 65 Hz */ + { 175000, 0x005d, 0x0018, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210c000, 0x22416000, 0x44419000, + 0x2210c000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 70 Hz */ + { 189000, 0x003D, 0x000e, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 72 Hz */ + { 195000, 0x003f, 0x000e, 0x10, 0x0b, 0xC7, 0xC7, 0x8f, 0xd5, 0x0b, + 0xE1, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xe2, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 75 Hz */ + { 202000, 0x0024, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 85 Hz */ + { 229000, 0x0029, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x22210000, 0x22416000, 0x0, + 0x22210000, 0x22416000, 0x0, 0x00 }, +}; + +void round_off_xres(u32 *xres) +{ + if (*xres < 800) + *xres = 640; + if (*xres < 1024 && *xres >= 800) + *xres = 800; + if (*xres < 1152 && *xres >= 1024) + *xres = 1024; + if (*xres < 1280 && *xres >= 1152) + *xres = 1152; + if (*xres < 1600 && *xres >= 1280) + *xres = 1280; + if (*xres >= 1600) + *xres = 1600; +} + +inline void round_off_yres(u32 *xres, u32 *yres) +{ + *yres = (*xres * 3) >> 2; +} + +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; + u8 hfl; + + hfl = (u8) ((xres >> 3) - 1); + for (i = 0; i < ARRAY_SIZE(std_modes); i++) { + if (std_modes[i].cr01 == hfl) { + if (std_modes[i].pixclock <= par->regs.pixclock) + diff = par->regs.pixclock - + std_modes[i].pixclock; + if (diff < diff_best) { + i_best = i; + diff_best = diff; + } + } + } + par->regs = std_modes[i_best]; + + /* overlay */ + par->ovract = ((xres + var->right_margin + var->hsync_len + + var->left_margin - 32) | ((xres - 32) << 16)); +} + +void i810fb_fill_var_timings(struct fb_var_screeninfo *var) +{ + struct i810fb_par par; + u32 total, xres, yres; + + xres = var->xres; + yres = var->yres; + + par.regs.pixclock = 1000000000/var->pixclock; + i810fb_encode_registers(var, &par, xres, yres); + + total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3; + + var->pixclock = 1000000000/par.regs.pixclock; + var->right_margin = (par.regs.cr04 << 3) - xres; + var->hsync_len = ((par.regs.cr05 & 0x1F) - + (par.regs.cr04 & 0x1F)) << 3; + var->left_margin = (total - (xres + var->right_margin + + var->hsync_len)); + var->sync = FB_SYNC_ON_GREEN; + if (~(par.regs.msr & (1 << 6))) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (~(par.regs.msr & (1 << 7))) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + + total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F) << 8)) + 2; + var->lower_margin = (par.regs.cr10 | + (par.regs.cr32 & 0x0F) << 8) - yres; + var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F); + var->upper_margin = total - (yres + var->lower_margin + + var->vsync_len); +} + +u32 i810_get_watermark(struct fb_var_screeninfo *var, + struct i810fb_par *par) +{ + struct mode_registers *params = &par->regs; + u32 wmark = 0; + + if (par->mem_freq == 100) { + switch (var->bits_per_pixel) { + case 8: + wmark = params->bpp8_100; + break; + case 16: + wmark = params->bpp16_100; + break; + case 24: + case 32: + wmark = params->bpp24_100; + } + } + else { + switch (var->bits_per_pixel) { + case 8: + wmark = params->bpp8_133; + break; + case 16: + wmark = params->bpp16_133; + break; + case 24: + case 32: + wmark = params->bpp24_133; + } + } + return wmark; +} + diff --git a/drivers/video/i810/i810_gtf.c b/drivers/video/i810/i810_gtf.c new file mode 100644 index 000000000000..d5edb52d1afe --- /dev/null +++ b/drivers/video/i810/i810_gtf.c @@ -0,0 +1,275 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_main.h -- Intel 810 Nondiscrete Video Timings + * (VESA GTF) + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/kernel.h> + +#include "i810_regs.h" +#include "i810.h" + +/* + * FIFO and Watermark tables - based almost wholly on i810_wmark.c in + * XFree86 v4.03 by Precision Insight. Slightly modified for integer + * operation, instead of float + */ + +struct wm_info { + u32 freq; + u32 wm; +}; + +struct wm_info i810_wm_8_100[] = { + { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 }, + { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 }, + { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 }, + { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 }, + { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 }, + { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 }, + { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 }, + { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 }, + { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 }, + { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, +}; + +struct wm_info i810_wm_16_100[] = { + { 15, 0x0070c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 }, + { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 }, + { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 }, + { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 }, + { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 }, + { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 }, + { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 }, + { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 }, + { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 }, + { 218, 0x22416000 }, { 229, 0x22416000 }, +}; + +struct wm_info i810_wm_24_100[] = { + { 15, 0x0020c000 }, { 19, 0x0040c000 }, { 25, 0x22009000 }, + { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 }, + { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 }, + { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 }, + { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 }, + { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 }, + { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 }, + { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 }, + { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 }, + { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 }, +}; + +struct wm_info i810_wm_8_133[] = { + { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 }, + { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 }, + { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 }, + { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 }, + { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 }, + { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 }, + { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 }, + { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 }, + { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 }, + { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, +}; + +struct wm_info i810_wm_16_133[] = { + { 15, 0x0020c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 }, + { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 }, + { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 }, + { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 }, + { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 }, + { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 }, + { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 }, + { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 }, + { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 }, + { 218, 0x22416000 }, { 229, 0x22416000 }, +}; + +struct wm_info i810_wm_24_133[] = { + { 15, 0x0020c000 }, { 19, 0x00408000 }, { 25, 0x22009000 }, + { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 }, + { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 }, + { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 }, + { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 }, + { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 }, + { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 }, + { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 }, + { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 }, + { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 }, +}; + +void round_off_xres(u32 *xres) { } +void round_off_yres(u32 *xres, u32 *yres) { } + +/** + * i810fb_encode_registers - encode @var to hardware register values + * @var: pointer to var structure + * @par: pointer to hardware par structure + * + * DESCRIPTION: + * Timing values in @var will be converted to appropriate + * register values of @par. + */ +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + int n, blank_s, blank_e; + u8 *mmio = par->mmio_start_virtual, msr = 0; + + /* Horizontal */ + /* htotal */ + n = ((xres + var->right_margin + var->hsync_len + + var->left_margin) >> 3) - 5; + par->regs.cr00 = (u8) n; + par->regs.cr35 = (u8) ((n >> 8) & 1); + + /* xres */ + par->regs.cr01 = (u8) ((xres >> 3) - 1); + + /* hblank */ + blank_e = (xres + var->right_margin + var->hsync_len + + var->left_margin) >> 3; + blank_e--; + blank_s = blank_e - 127; + if (blank_s < (xres >> 3)) + blank_s = xres >> 3; + par->regs.cr02 = (u8) blank_s; + par->regs.cr03 = (u8) (blank_e & 0x1F); + par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2); + par->regs.cr39 = (u8) ((blank_e >> 6) & 1); + + /* hsync */ + par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3); + par->regs.cr05 |= (u8) (((xres + var->right_margin + + var->hsync_len) >> 3) & 0x1F); + + /* Vertical */ + /* vtotal */ + n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2; + par->regs.cr06 = (u8) (n & 0xFF); + par->regs.cr30 = (u8) ((n >> 8) & 0x0F); + + /* vsync */ + n = yres + var->lower_margin; + par->regs.cr10 = (u8) (n & 0xFF); + par->regs.cr32 = (u8) ((n >> 8) & 0x0F); + par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F; + par->regs.cr11 |= (u8) ((yres + var->lower_margin + + var->vsync_len) & 0x0F); + + /* yres */ + n = yres - 1; + par->regs.cr12 = (u8) (n & 0xFF); + par->regs.cr31 = (u8) ((n >> 8) & 0x0F); + + /* vblank */ + blank_e = yres + var->lower_margin + var->vsync_len + + var->upper_margin; + blank_e--; + blank_s = blank_e - 127; + if (blank_s < yres) + blank_s = yres; + par->regs.cr15 = (u8) (blank_s & 0xFF); + par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F); + par->regs.cr16 = (u8) (blank_e & 0xFF); + par->regs.cr09 = 0; + + /* sync polarity */ + if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) + msr |= 1 << 6; + if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) + msr |= 1 << 7; + par->regs.msr = msr; + + /* interlace */ + if (var->vmode & FB_VMODE_INTERLACED) + par->interlace = (1 << 7) | ((u8) (var->yres >> 4)); + else + par->interlace = 0; + + if (var->vmode & FB_VMODE_DOUBLE) + par->regs.cr09 |= 1 << 7; + + /* overlay */ + par->ovract = ((var->xres + var->right_margin + var->hsync_len + + var->left_margin - 32) | ((var->xres - 32) << 16)); +} + +void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { } + +/** + * i810_get_watermark - gets watermark + * @var: pointer to fb_var_screeninfo + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Get's the required watermark based on + * pixelclock and RAMBUS frequency. + * + * RETURNS: + * watermark + */ +u32 i810_get_watermark(const struct fb_var_screeninfo *var, + struct i810fb_par *par) +{ + struct wm_info *wmark = 0; + u32 i, size = 0, pixclock, wm_best = 0, min, diff; + + if (par->mem_freq == 100) { + switch (var->bits_per_pixel) { + case 8: + wmark = i810_wm_8_100; + size = ARRAY_SIZE(i810_wm_8_100); + break; + case 16: + wmark = i810_wm_16_100; + size = ARRAY_SIZE(i810_wm_16_100); + break; + case 24: + case 32: + wmark = i810_wm_24_100; + size = ARRAY_SIZE(i810_wm_24_100); + } + } + else { + switch(var->bits_per_pixel) { + case 8: + wmark = i810_wm_8_133; + size = ARRAY_SIZE(i810_wm_8_133); + break; + case 16: + wmark = i810_wm_16_133; + size = ARRAY_SIZE(i810_wm_16_133); + break; + case 24: + case 32: + wmark = i810_wm_24_133; + size = ARRAY_SIZE(i810_wm_24_133); + } + } + + pixclock = 1000000/var->pixclock; + min = ~0; + for (i = 0; i < size; i++) { + if (pixclock <= wmark[i].freq) + diff = wmark[i].freq - pixclock; + else + diff = pixclock - wmark[i].freq; + if (diff < min) { + wm_best = wmark[i].wm; + min = diff; + } + } + return wm_best; +} + diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c new file mode 100644 index 000000000000..a13b75cefae4 --- /dev/null +++ b/drivers/video/i810/i810_main.c @@ -0,0 +1,2245 @@ + /*-*- linux-c -*- + * linux/drivers/video/i810_main.c -- Intel 810 frame buffer device + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * Contributors: + * Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets + * and enabling the power-on state of + * external VGA connectors for + * secondary displays + * + * Fredrik Andersson <krueger@shell.linux.se> - alpha testing of + * the VESA GTF + * + * Brad Corrion <bcorrion@web-co.com> - alpha testing of customized + * timings support + * + * The code framework is a modification of vfb.c by Geert Uytterhoeven. + * DotClock and PLL calculations are partly based on i810_driver.c + * in xfree86 v4.0.3 by Precision Insight. + * Watermark calculation and tables are based on i810_wmark.c + * in xfre86 v4.0.3 by Precision Insight. Slight modifications + * only to allow for integer operations instead of floating point. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/resource.h> +#include <linux/unistd.h> + +#include <asm/io.h> +#include <asm/div64.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <asm/page.h> + +#include "i810_regs.h" +#include "i810.h" +#include "i810_main.h" + +/*------------------------------------------------------------*/ + +/************************************************************** + * Hardware Low Level Routines * + **************************************************************/ + +/** + * i810_screen_off - turns off/on display + * @mmio: address of register space + * @mode: on or off + * + * DESCRIPTION: + * Blanks/unblanks the display + */ +static void i810_screen_off(u8 *mmio, u8 mode) +{ + u32 count = WAIT_COUNT; + u8 val; + + i810_writeb(SR_INDEX, mmio, SR01); + val = i810_readb(SR_DATA, mmio); + val = (mode == OFF) ? val | SCR_OFF : + val & ~SCR_OFF; + + while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--); + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, val); +} + +/** + * i810_dram_off - turns off/on dram refresh + * @mmio: address of register space + * @mode: on or off + * + * DESCRIPTION: + * Turns off DRAM refresh. Must be off for only 2 vsyncs + * before data becomes corrupt + */ +static void i810_dram_off(u8 *mmio, u8 mode) +{ + u8 val; + + val = i810_readb(DRAMCH, mmio); + val &= DRAM_OFF; + val = (mode == OFF) ? val : val | DRAM_ON; + i810_writeb(DRAMCH, mmio, val); +} + +/** + * i810_protect_regs - allows rw/ro mode of certain VGA registers + * @mmio: address of register space + * @mode: protect/unprotect + * + * DESCRIPTION: + * The IBM VGA standard allows protection of certain VGA registers. + * This will protect or unprotect them. + */ +static void i810_protect_regs(u8 *mmio, int mode) +{ + u8 reg; + + i810_writeb(CR_INDEX_CGA, mmio, CR11); + reg = i810_readb(CR_DATA_CGA, mmio); + reg = (mode == OFF) ? reg & ~0x80 : + reg | 0x80; + + i810_writeb(CR_INDEX_CGA, mmio, CR11); + i810_writeb(CR_DATA_CGA, mmio, reg); +} + +/** + * i810_load_pll - loads values for the hardware PLL clock + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the P, M, and N registers. + */ +static void i810_load_pll(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 *mmio = par->mmio_start_virtual; + + tmp1 = par->regs.M | par->regs.N << 16; + tmp2 = i810_readl(DCLK_2D, mmio); + tmp2 &= ~MN_MASK; + i810_writel(DCLK_2D, mmio, tmp1 | tmp2); + + tmp1 = par->regs.P; + tmp2 = i810_readl(DCLK_0DS, mmio); + tmp2 &= ~(P_OR << 16); + i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2); + + i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1); + +} + +/** + * i810_load_vga - load standard VGA registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to VGA registers + */ +static void i810_load_vga(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + /* interlace */ + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i810_writeb(CR_DATA_CGA, mmio, par->interlace); + + i810_writeb(CR_INDEX_CGA, mmio, CR00); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00); + i810_writeb(CR_INDEX_CGA, mmio, CR01); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01); + i810_writeb(CR_INDEX_CGA, mmio, CR02); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02); + i810_writeb(CR_INDEX_CGA, mmio, CR03); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03); + i810_writeb(CR_INDEX_CGA, mmio, CR04); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04); + i810_writeb(CR_INDEX_CGA, mmio, CR05); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05); + i810_writeb(CR_INDEX_CGA, mmio, CR06); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06); + i810_writeb(CR_INDEX_CGA, mmio, CR09); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09); + i810_writeb(CR_INDEX_CGA, mmio, CR10); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10); + i810_writeb(CR_INDEX_CGA, mmio, CR11); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11); + i810_writeb(CR_INDEX_CGA, mmio, CR12); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12); + i810_writeb(CR_INDEX_CGA, mmio, CR15); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15); + i810_writeb(CR_INDEX_CGA, mmio, CR16); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16); +} + +/** + * i810_load_vgax - load extended VGA registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to extended VGA registers + */ +static void i810_load_vgax(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + i810_writeb(CR_INDEX_CGA, mmio, CR30); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30); + i810_writeb(CR_INDEX_CGA, mmio, CR31); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31); + i810_writeb(CR_INDEX_CGA, mmio, CR32); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32); + i810_writeb(CR_INDEX_CGA, mmio, CR33); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33); + i810_writeb(CR_INDEX_CGA, mmio, CR35); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39); +} + +/** + * i810_load_2d - load grahics registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to graphics registers + */ +static void i810_load_2d(struct i810fb_par *par) +{ + u32 tmp; + u8 tmp8, *mmio = par->mmio_start_virtual;; + + i810_writel(FW_BLC, mmio, par->watermark); + tmp = i810_readl(PIXCONF, mmio); + tmp |= 1 | 1 << 20; + i810_writel(PIXCONF, mmio, tmp); + + i810_writel(OVRACT, mmio, par->ovract); + + i810_writeb(GR_INDEX, mmio, GR10); + tmp8 = i810_readb(GR_DATA, mmio); + tmp8 |= 2; + i810_writeb(GR_INDEX, mmio, GR10); + i810_writeb(GR_DATA, mmio, tmp8); +} + +/** + * i810_hires - enables high resolution mode + * @mmio: address of register space + */ +static void i810_hires(u8 *mmio) +{ + u8 val; + + i810_writeb(CR_INDEX_CGA, mmio, CR80); + val = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR80); + i810_writeb(CR_DATA_CGA, mmio, val | 1); +} + +/** + * i810_load_pitch - loads the characters per line of the display + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the characters per line + */ +static void i810_load_pitch(struct i810fb_par *par) +{ + u32 tmp, pitch; + u8 val, *mmio = par->mmio_start_virtual; + + pitch = par->pitch >> 3; + i810_writeb(SR_INDEX, mmio, SR01); + val = i810_readb(SR_DATA, mmio); + val &= 0xE0; + val |= 1 | 1 << 2; + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, val); + + tmp = pitch & 0xFF; + i810_writeb(CR_INDEX_CGA, mmio, CR13); + i810_writeb(CR_DATA_CGA, mmio, (u8) tmp); + + tmp = pitch >> 8; + i810_writeb(CR_INDEX_CGA, mmio, CR41); + val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F; + i810_writeb(CR_INDEX_CGA, mmio, CR41); + i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val); +} + +/** + * i810_load_color - loads the color depth of the display + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the color depth of the display and the graphics engine + */ +static void i810_load_color(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + u32 reg1; + u16 reg2; + reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27); + reg2 = i810_readw(BLTCNTL, mmio) & ~0x30; + + reg1 |= 0x8000 | par->pixconf; + reg2 |= par->bltcntl; + i810_writel(PIXCONF, mmio, reg1); + i810_writew(BLTCNTL, mmio, reg2); +} + +/** + * i810_load_regs - loads all registers for the mode + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads registers + */ +static void i810_load_regs(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + i810_screen_off(mmio, OFF); + i810_protect_regs(mmio, OFF); + i810_dram_off(mmio, OFF); + i810_load_pll(par); + i810_load_vga(par); + i810_load_vgax(par); + i810_dram_off(mmio, ON); + i810_load_2d(par); + i810_hires(mmio); + i810_screen_off(mmio, ON); + i810_protect_regs(mmio, ON); + i810_load_color(par); + i810_load_pitch(par); +} + +static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue, + u8 *mmio) +{ + i810_writeb(CLUT_INDEX_WRITE, mmio, regno); + i810_writeb(CLUT_DATA, mmio, red); + i810_writeb(CLUT_DATA, mmio, green); + i810_writeb(CLUT_DATA, mmio, blue); +} + +static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue, + u8 *mmio) +{ + i810_writeb(CLUT_INDEX_READ, mmio, regno); + *red = i810_readb(CLUT_DATA, mmio); + *green = i810_readb(CLUT_DATA, mmio); + *blue = i810_readb(CLUT_DATA, mmio); +} + +/************************************************************ + * VGA State Restore * + ************************************************************/ +static void i810_restore_pll(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 *mmio = par->mmio_start_virtual; + + tmp1 = par->hw_state.dclk_2d; + tmp2 = i810_readl(DCLK_2D, mmio); + tmp1 &= ~MN_MASK; + tmp2 &= MN_MASK; + i810_writel(DCLK_2D, mmio, tmp1 | tmp2); + + tmp1 = par->hw_state.dclk_1d; + tmp2 = i810_readl(DCLK_1D, mmio); + tmp1 &= ~MN_MASK; + tmp2 &= MN_MASK; + i810_writel(DCLK_1D, mmio, tmp1 | tmp2); + + i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds); +} + +static void i810_restore_dac(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 *mmio = par->mmio_start_virtual; + + tmp1 = par->hw_state.pixconf; + tmp2 = i810_readl(PIXCONF, mmio); + tmp1 &= DAC_BIT; + tmp2 &= ~DAC_BIT; + i810_writel(PIXCONF, mmio, tmp1 | tmp2); +} + +static void i810_restore_vgax(struct i810fb_par *par) +{ + u8 i, j, *mmio = par->mmio_start_virtual; + + for (i = 0; i < 4; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR30+i); + i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i)); + } + i810_writeb(CR_INDEX_CGA, mmio, CR35); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39); + i810_writeb(CR_INDEX_CGA, mmio, CR41); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39); + + /*restore interlace*/ + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i = par->hw_state.cr70; + i &= INTERLACE_BIT; + j = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i810_writeb(CR_DATA_CGA, mmio, j | i); + + i810_writeb(CR_INDEX_CGA, mmio, CR80); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80); + i810_writeb(MSR_WRITE, mmio, par->hw_state.msr); + i810_writeb(SR_INDEX, mmio, SR01); + i = (par->hw_state.sr01) & ~0xE0 ; + j = i810_readb(SR_DATA, mmio) & 0xE0; + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, i | j); +} + +static void i810_restore_vga(struct i810fb_par *par) +{ + u8 i, *mmio = par->mmio_start_virtual; + + for (i = 0; i < 10; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); + i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i)); + } + for (i = 0; i < 8; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR10 + i); + i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i)); + } +} + +static void i810_restore_addr_map(struct i810fb_par *par) +{ + u8 tmp, *mmio = par->mmio_start_virtual; + + i810_writeb(GR_INDEX, mmio, GR10); + tmp = i810_readb(GR_DATA, mmio); + tmp &= ADDR_MAP_MASK; + tmp |= par->hw_state.gr10; + i810_writeb(GR_INDEX, mmio, GR10); + i810_writeb(GR_DATA, mmio, tmp); +} + +static void i810_restore_2d(struct i810fb_par *par) +{ + u32 tmp_long; + u16 tmp_word; + u8 *mmio = par->mmio_start_virtual; + + tmp_word = i810_readw(BLTCNTL, mmio); + tmp_word &= ~(3 << 4); + tmp_word |= par->hw_state.bltcntl; + i810_writew(BLTCNTL, mmio, tmp_word); + + i810_dram_off(mmio, OFF); + i810_writel(PIXCONF, mmio, par->hw_state.pixconf); + i810_dram_off(mmio, ON); + + tmp_word = i810_readw(HWSTAM, mmio); + tmp_word &= 3 << 13; + tmp_word |= par->hw_state.hwstam; + i810_writew(HWSTAM, mmio, tmp_word); + + tmp_long = i810_readl(FW_BLC, mmio); + tmp_long &= FW_BLC_MASK; + tmp_long |= par->hw_state.fw_blc; + i810_writel(FW_BLC, mmio, tmp_long); + + i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga); + i810_writew(IER, mmio, par->hw_state.ier); + i810_writew(IMR, mmio, par->hw_state.imr); + i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas); +} + +static void i810_restore_vga_state(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + i810_screen_off(mmio, OFF); + i810_protect_regs(mmio, OFF); + i810_dram_off(mmio, OFF); + i810_restore_pll(par); + i810_restore_dac(par); + i810_restore_vga(par); + i810_restore_vgax(par); + i810_restore_addr_map(par); + i810_dram_off(mmio, ON); + i810_restore_2d(par); + i810_screen_off(mmio, ON); + i810_protect_regs(mmio, ON); +} + +/*********************************************************************** + * VGA State Save * + ***********************************************************************/ + +static void i810_save_vgax(struct i810fb_par *par) +{ + u8 i, *mmio = par->mmio_start_virtual; + + for (i = 0; i < 4; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR30 + i); + *(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio); + } + i810_writeb(CR_INDEX_CGA, mmio, CR35); + par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR41); + par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR70); + par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio); + par->hw_state.msr = i810_readb(MSR_READ, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR80); + par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(SR_INDEX, mmio, SR01); + par->hw_state.sr01 = i810_readb(SR_DATA, mmio); +} + +static void i810_save_vga(struct i810fb_par *par) +{ + u8 i, *mmio = par->mmio_start_virtual; + + for (i = 0; i < 10; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); + *((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio); + } + for (i = 0; i < 8; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR10 + i); + *((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio); + } +} + +static void i810_save_2d(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio); + par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio); + par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio); + par->hw_state.pixconf = i810_readl(PIXCONF, mmio); + par->hw_state.fw_blc = i810_readl(FW_BLC, mmio); + par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio); + par->hw_state.hwstam = i810_readw(HWSTAM, mmio); + par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); + par->hw_state.ier = i810_readw(IER, mmio); + par->hw_state.imr = i810_readw(IMR, mmio); + par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio); +} + +static void i810_save_vga_state(struct i810fb_par *par) +{ + i810_save_vga(par); + i810_save_vgax(par); + i810_save_2d(par); +} + +/************************************************************ + * Helpers * + ************************************************************/ +/** + * get_line_length - calculates buffer pitch in bytes + * @par: pointer to i810fb_par structure + * @xres_virtual: virtual resolution of the frame + * @bpp: bits per pixel + * + * DESCRIPTION: + * Calculates buffer pitch in bytes. + */ +u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp) +{ + u32 length; + + length = xres_virtual*bpp; + length = (length+31)&-32; + length >>= 3; + return length; +} + +/** + * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value + * @freq: target pixelclock in picoseconds + * @m: where to write M register + * @n: where to write N register + * @p: where to write P register + * + * DESCRIPTION: + * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P) + * Repeatedly computes the Freq until the actual Freq is equal to + * the target Freq or until the loop count is zero. In the latter + * case, the actual frequency nearest the target will be used. + */ +static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p) +{ + u32 m_reg, n_reg, p_divisor, n_target_max; + u32 m_target, n_target, p_target, n_best, m_best, mod; + u32 f_out, target_freq, diff = 0, mod_min, diff_min; + + diff_min = mod_min = 0xFFFFFFFF; + n_best = m_best = m_target = f_out = 0; + + target_freq = freq; + n_target_max = 30; + + /* + * find P such that target freq is 16x reference freq (Hz). + */ + p_divisor = 1; + p_target = 0; + while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && + p_divisor <= 32) { + p_divisor <<= 1; + p_target++; + } + + n_reg = m_reg = n_target = 3; + while ((diff_min || mod_min) && (n_target < n_target_max)) { + f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg); + mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg); + m_target = m_reg; + n_target = n_reg; + if (f_out <= target_freq) { + n_reg++; + diff = target_freq - f_out; + } + else { + m_reg++; + diff = f_out - target_freq; + } + + if (diff_min > diff) { + diff_min = diff; + n_best = n_target; + m_best = m_target; + } + + if (!diff && mod_min > mod) { + mod_min = mod; + n_best = n_target; + m_best = m_target; + } + } + if (m) *m = (m_best - 2) & 0x3FF; + if (n) *n = (n_best - 2) & 0x3FF; + if (p) *p = (p_target << 4); +} + +/** + * i810_get_vblank - get vertical blank time + * @hfreq: horizontal freq + * + * DESCRIPTION: + * vblank = right_margin + vsync_len + left_margin + * given: right_margin = 1 (V_FRONTPORCH) + * vsync_len = 3 + * flyback = 550 + * + * flyback * hfreq + * left_margin = --------------- - vsync_len + * 1000000 + * and flyback is set to 550 + */ +static u32 i810_get_vblank(u32 hfreq) +{ + u32 vblank; + + vblank = (hfreq * FLYBACK)/1000; + vblank = (vblank + 500)/1000; + return (vblank + V_FRONTPORCH); +} + +/** + * i810_get_hblank - get horizontal blank time + * @hfreq: horizontal freq + * @xres: horizontal resolution in pixels + * + * DESCRIPTION: + * duty cycle is the percent of htotal assigned to inactive display + * duty cycle = C - (M/Hfreq) + * where: C = ((offset - scale factor) * blank_scale) + * -------------------------------------- + scale factor + * 256 + * M = blank_scale * gradient + * + * xres * duty_cycle + * hblank = ------------------ + * 100 - duty_cycle + */ +static u32 i810_get_hblank(u32 hfreq, u32 xres) +{ + u32 c_val, m_val, duty_cycle, hblank; + + c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + + H_SCALEFACTOR) * 1000; + m_val = (H_BLANKSCALE * H_GRADIENT)/256; + m_val = (m_val * 1000000)/hfreq; + duty_cycle = c_val - m_val; + hblank = (xres * duty_cycle)/(100000 - duty_cycle); + hblank = (hblank + 4) & ~7; + return (hblank); +} + +/** + * i810_estimate_hfreq - estimate hsync + * @vfreq: vertical refresh rate + * @yres: vertical resolution + * + * DESCRIPTION: + * Based on: + * + * (yres + front_port) * vfreq * 1000000 + * hfreq = ------------------------------------- + * (1000000 - (vfreq * FLYBACK) + * + */ + +static u32 i810_estimate_hfreq(u32 vfreq, u32 yres) +{ + u64 hfreq; + u32 divisor; + + divisor = 1000000 - (vfreq * FLYBACK); + + hfreq = (u64) (yres + V_FRONTPORCH) * + (u64) (vfreq) * 1000000; + do_div(hfreq, divisor); + + return ((u32) hfreq); +} + +/** + * i810_calculate_timings - calculate video timings + * @info: pointer to fb_info structure + * @var: pointer to current var + * + * DESCRIPTION: + * htotal: calculated using GTF + * vtotal: calculated using GTF + * hsync pulse: 8% of htotal + * vsync pulse: 3 + * left margin : (htotal - xres)/2 - hsync + * right margin: sync + left margin + * upper margin: 1 + * lower margin: vtotal - (yres + vsync + upper margin) + * + * Calculates necessary timing information based on + * monitor specifications. This will use the + * VESA generalized timing formula. New values are + * written to @var. + */ +static int i810_calculate_timings(struct fb_info *info, + struct fb_var_screeninfo *var, + u32 xres, u32 yres) +{ + u64 num = 1000000000000; + u32 htotal = 0, vtotal, hfreq, vfreq, hblank, vblank; + u32 dclk, interlace = 0, dscan = 0; + u32 max_pixclock = 0; + + switch (var->bits_per_pixel) { + case 8: + max_pixclock = 234000000; + break; + case 16: + max_pixclock = 229000000; + break; + case 24: + case 32: + max_pixclock = 204000000; + break; + default: + max_pixclock = 0; + } + + if (var->vmode & FB_VMODE_INTERLACED) { + yres >>= 1; + interlace = 1; + } + if (var->vmode & FB_VMODE_DOUBLE) { + yres <<= 1; + dscan = 1; + } + + hfreq = info->monspecs.hfmax; + vblank = i810_get_vblank(hfreq); + vtotal = yres + vblank; + vfreq = hfreq/vtotal; + if (vfreq > info->monspecs.vfmax) { + vfreq = info->monspecs.vfmax; + hfreq = i810_estimate_hfreq(vfreq, yres); + vblank = i810_get_vblank(hfreq); + vtotal = yres + vblank; + } + hblank = i810_get_hblank(hfreq, xres); + htotal = xres + hblank; + dclk = htotal * hfreq; + while(dclk > max_pixclock && + hfreq > info->monspecs.hfmin && + vfreq > info->monspecs.vfmin) { + hfreq -= 1000; + vblank = i810_get_vblank(hfreq); + vtotal = yres + vblank; + vfreq = hfreq/vtotal; + hblank = i810_get_hblank(hfreq, xres); + htotal = xres + hblank; + dclk = hfreq * htotal; + } + if (vfreq < info->monspecs.vfmin) { + printk("i810fb: required vertical refresh, %dHz, " + "for %dx%d is out of range\n", + vfreq, xres, yres); + return -1; + } + if (hfreq < info->monspecs.hfmin) { + printk("i810fb: required horizontal sync frequency, %dKHz, " + "for %dx%d is out of range\n", hfreq/1000, xres, yres); + return -1; + } + if (dclk < MIN_PIXELCLOCK) { + printk("i810fb: required pixelclock, %dMHz, for %dx%d" + " is out of range\n", dclk/1000000, xres, yres); + return -1; + } + + do_div(num, dclk); + var->pixclock = (u32) num; + var->hsync_len = ((htotal * 8)/100 + 4) & ~7; + var->right_margin = ((hblank >> 1) - var->hsync_len + 4) & ~7; + var->left_margin = (hblank-var->right_margin-var->hsync_len + 4) & ~7; + + var->vsync_len = (3 << interlace) >> dscan; + var->lower_margin = (1 << interlace) >> dscan; + var->upper_margin = ((vblank << interlace) >> dscan) - + (var->vsync_len + var->lower_margin); + + if (yres > 480 || (yres == 200 && vfreq == 60 && hfreq/100 == 157)) + var->sync |= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT; + else { + if (yres == 400 && vfreq == 70 && hfreq/100 == 315) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (yres == 350 && vfreq == 60 && hfreq/100 == 218) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + } + return 0; +} + +/** + * i810_check_custom_timings - validates user entered timings + * @info: pointer to fb_info + * @var: pointer to current fb_var_screeninfo + * + * DESCRIPTION: + * Validates user entered timings in @var. + */ +static int i810_check_custom_timings(struct fb_info *info, + struct fb_var_screeninfo *var, + u32 xres, u32 yres) +{ + u64 num = 1000000000000; + u32 hfreq, vfreq, htotal, vtotal, pixclock; + u32 max_pixclock = 0; + + if (!var->pixclock) + return -EINVAL; + do_div(num, var->pixclock); + pixclock = (u32) num; + + htotal = xres + var->right_margin + var->hsync_len + var->left_margin; + vtotal = yres + var->lower_margin + var->vsync_len + var->upper_margin; + + if (var->vmode & FB_VMODE_INTERLACED) + vtotal >>= 1; + + if (var->vmode & FB_VMODE_DOUBLE) + vtotal <<= 1; + + hfreq = pixclock/htotal; + vfreq = hfreq/vtotal; + + switch (var->bits_per_pixel) { + case 8: + max_pixclock = 234000000; + break; + case 16: + max_pixclock = 229000000; + break; + case 24: + case 32: + max_pixclock = 204000000; + break; + default: + max_pixclock = 0; + } + + if (pixclock < MIN_PIXELCLOCK || pixclock > max_pixclock || + hfreq < info->monspecs.hfmin || hfreq > info->monspecs.hfmax || + vfreq < info->monspecs.vfmin || vfreq > info->monspecs.vfmax) + return -EINVAL; + + return 0; +} + +/************************************************************* + * Hardware Cursor Routines * + *************************************************************/ + +/** + * i810_enable_cursor - show or hide the hardware cursor + * @mmio: address of register space + * @mode: show (1) or hide (0) + * + * Description: + * Shows or hides the hardware cursor + */ +void i810_enable_cursor(u8 *mmio, int mode) +{ + u32 temp; + + temp = i810_readl(PIXCONF, mmio); + temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK : + temp & ~CURSOR_ENABLE_MASK; + + i810_writel(PIXCONF, mmio, temp); +} + +static void i810_reset_cursor_image(struct i810fb_par *par) +{ + u8 *addr = par->cursor_heap.virtual; + int i, j; + + for (i = 64; i--; ) { + for (j = 0; j < 8; j++) { + i810_writeb(j, addr, 0xff); + i810_writeb(j+8, addr, 0x00); + } + addr +=16; + } +} + +static void i810_load_cursor_image(int width, int height, u8 *data, + struct i810fb_par *par) +{ + u8 *addr = par->cursor_heap.virtual; + int i, j, w = (width + 7)/8; + + for (i = height; i--; ) { + for (j = 0; j < w; j++) { + i810_writeb(j+0, addr, 0x00); + i810_writeb(j+8, addr, *data++); + } + addr += 16; + } +} + +static void i810_load_cursor_colors(int fg, int bg, + struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 *mmio = par->mmio_start_virtual, temp; + u8 red, green, blue, trans; + + i810fb_getcolreg(bg, &red, &green, &blue, &trans, info); + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); + + i810_write_dac(4, red, green, blue, mmio); + + i810_writeb(PIXCONF1, mmio, temp); + + i810fb_getcolreg(fg, &red, &green, &blue, &trans, info); + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); + + i810_write_dac(5, red, green, blue, mmio); + + i810_writeb(PIXCONF1, mmio, temp); +} + +/** + * i810_init_cursor - initializes the cursor + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Initializes the cursor registers + */ +static void i810_init_cursor(struct i810fb_par *par) +{ + u8 *mmio = par->mmio_start_virtual; + + i810_enable_cursor(mmio, OFF); + i810_writel(CURBASE, mmio, par->cursor_heap.physical); + i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR); +} + +/********************************************************************* + * Framebuffer hook helpers * + *********************************************************************/ +/** + * i810_round_off - Round off values to capability of hardware + * @var: pointer to fb_var_screeninfo structure + * + * DESCRIPTION: + * @var contains user-defined information for the mode to be set. + * This will try modify those values to ones nearest the + * capability of the hardware + */ +static void i810_round_off(struct fb_var_screeninfo *var) +{ + u32 xres, yres, vxres, vyres; + + /* + * Presently supports only these configurations + */ + + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + + var->bits_per_pixel += 7; + var->bits_per_pixel &= ~7; + + if (var->bits_per_pixel < 8) + var->bits_per_pixel = 8; + if (var->bits_per_pixel > 32) + var->bits_per_pixel = 32; + + round_off_xres(&xres); + if (xres < 40) + xres = 40; + if (xres > 2048) + xres = 2048; + xres = (xres + 7) & ~7; + + if (vxres < xres) + vxres = xres; + + round_off_yres(&xres, &yres); + if (yres < 1) + yres = 1; + if (yres >= 2048) + yres = 2048; + + if (vyres < yres) + vyres = yres; + + if (var->bits_per_pixel == 32) + var->accel_flags = 0; + + /* round of horizontal timings to nearest 8 pixels */ + var->left_margin = (var->left_margin + 4) & ~7; + var->right_margin = (var->right_margin + 4) & ~7; + var->hsync_len = (var->hsync_len + 4) & ~7; + + if (var->vmode & FB_VMODE_INTERLACED) { + if (!((yres + var->upper_margin + var->vsync_len + + var->lower_margin) & 1)) + var->upper_margin++; + } + + var->xres = xres; + var->yres = yres; + var->xres_virtual = vxres; + var->yres_virtual = vyres; +} + +/** + * set_color_bitfields - sets rgba fields + * @var: pointer to fb_var_screeninfo + * + * DESCRIPTION: + * The length, offset and ordering for each color field + * (red, green, blue) will be set as specified + * by the hardware + */ +static void set_color_bitfields(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: + if (var->green.length == 5) { + /* RGB 555 */ + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } + else { + /* RGB 565 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + break; + case 24: /* RGB 888 */ + case 32: /* RGBA 8888 */ + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + if (var->bits_per_pixel == 24) { + var->transp.offset = 0; + var->transp.length = 0; + } + else { + var->transp.offset = 24; + var->transp.length = 8; + break; + } + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; +} + +/** + * i810_check_params - check if contents in var are valid + * @var: pointer to fb_var_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * This will check if the framebuffer size is sufficient + * for the current mode and if the user's monitor has the + * required specifications to display the current mode. + */ +static int i810_check_params(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + int line_length, vidmem; + u32 xres, yres, vxres, vyres; + + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + + /* + * Memory limit + */ + line_length = get_line_length(par, vxres, + var->bits_per_pixel); + + vidmem = line_length*vyres; + if (vidmem > par->fb.size) { + vyres = par->fb.size/line_length; + if (vyres < yres) { + vyres = yres; + vxres = par->fb.size/vyres; + vxres /= var->bits_per_pixel >> 3; + line_length = get_line_length(par, vxres, + var->bits_per_pixel); + vidmem = line_length * yres; + if (vxres < xres) { + printk("i810fb: required video memory, " + "%d bytes, for %dx%d-%d (virtual) " + "is out of range\n", + vidmem, vxres, vyres, + var->bits_per_pixel); + return -ENOMEM; + } + } + } + /* + * Monitor limit + */ + if (i810_check_custom_timings(info, var, xres, yres)) { + if (i810_calculate_timings(info, var, xres, yres)) { + return -EINVAL; + } + } + var->xres = xres; + var->yres = yres; + var->xres_virtual = vxres; + var->yres_virtual = vyres; + return 0; +} + +/** + * encode_fix - fill up fb_fix_screeninfo structure + * @fix: pointer to fb_fix_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * This will set up parameters that are unmodifiable by the user. + */ +static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, i810fb_name); + fix->smem_start = par->fb.physical; + fix->smem_len = par->fb.size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->xpanstep = 8; + fix->ypanstep = 1; + + switch (info->var.bits_per_pixel) { + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + case 24: + case 32: + if (info->var.nonstd) + fix->visual = FB_VISUAL_DIRECTCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; + break; + default: + return -EINVAL; + } + fix->ywrapstep = 0; + fix->line_length = get_line_length(par, info->var.xres_virtual, + info->var.bits_per_pixel); + fix->mmio_start = par->mmio_start_phys; + fix->mmio_len = MMIO_SIZE; + fix->accel = FB_ACCEL_I810; + + return 0; +} + +/** + * decode_var - modify par according to contents of var + * @var: pointer to fb_var_screeninfo + * @par: pointer to i810fb_par + * @info: pointer to fb_info + * + * DESCRIPTION: + * Based on the contents of @var, @par will be dynamically filled up. + * @par contains all information necessary to modify the hardware. +*/ +static void decode_var(const struct fb_var_screeninfo *var, + struct i810fb_par *par, struct fb_info *info) +{ + u32 xres, yres, vxres, vyres; + + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + + switch (var->bits_per_pixel) { + case 8: + par->pixconf = PIXCONF8; + par->bltcntl = 0; + par->depth = 1; + par->blit_bpp = BPP8; + break; + case 16: + if (var->green.length == 5) + par->pixconf = PIXCONF15; + else + par->pixconf = PIXCONF16; + par->bltcntl = 16; + par->depth = 2; + par->blit_bpp = BPP16; + break; + case 24: + par->pixconf = PIXCONF24; + par->bltcntl = 32; + par->depth = 3; + par->blit_bpp = BPP24; + break; + case 32: + par->pixconf = PIXCONF32; + par->bltcntl = 0; + par->depth = 4; + par->blit_bpp = 3 << 24; + break; + } + if (var->nonstd && var->bits_per_pixel != 8) + par->pixconf |= 1 << 27; + + i810_calc_dclk(var->pixclock, &par->regs.M, + &par->regs.N, &par->regs.P); + i810fb_encode_registers(var, par, xres, yres); + + par->watermark = i810_get_watermark(var, par); + par->pitch = get_line_length(par, vxres, var->bits_per_pixel); +} + +/** + * i810fb_getcolreg - gets red, green and blue values of the hardware DAC + * @regno: DAC index + * @red: red + * @green: green + * @blue: blue + * @transp: transparency (alpha) + * @info: pointer to fb_info + * + * DESCRIPTION: + * Gets the red, green and blue values of the hardware DAC as pointed by @regno + * and writes them to @red, @green and @blue respectively + */ +static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, + u8 *transp, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 *mmio = par->mmio_start_virtual, temp; + + if (regno > 255) return 1; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if ((info->var.green.length == 5 && regno > 31) || + (info->var.green.length == 6 && regno > 63)) + return 1; + } + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 5) + i810_read_dac(regno * 8, red, green, blue, mmio); + + else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 6) { + u8 tmp; + + i810_read_dac(regno * 8, red, &tmp, blue, mmio); + i810_read_dac(regno * 4, &tmp, green, &tmp, mmio); + } + else + i810_read_dac(regno, red, green, blue, mmio); + + *transp = 0; + i810_writeb(PIXCONF1, mmio, temp); + + return 0; +} + +/****************************************************************** + * Framebuffer device-specific hooks * + ******************************************************************/ + +static int i810fb_open(struct fb_info *info, int user) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 count = atomic_read(&par->use_count); + + if (count == 0) { + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_CMAP; + par->state.vgabase = (caddr_t) par->mmio_start_virtual; + save_vga(&par->state); + + i810_save_vga_state(par); + } + + atomic_inc(&par->use_count); + + return 0; +} + +static int i810fb_release(struct fb_info *info, int user) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 count; + + count = atomic_read(&par->use_count); + if (count == 0) + return -EINVAL; + + if (count == 1) { + i810_restore_vga_state(par); + restore_vga(&par->state); + } + + atomic_dec(&par->use_count); + + return 0; +} + + +static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 *mmio = par->mmio_start_virtual, temp; + int i; + + if (regno > 255) return 1; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if ((info->var.green.length == 5 && regno > 31) || + (info->var.green.length == 6 && regno > 63)) + return 1; + } + + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 5) { + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, (u8) red, + (u8) green, (u8) blue, mmio); + } + + else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 6) { + if (!regno) { + memset(par->red, 0, 64); + memset(par->green, 0, 64); + memset(par->blue, 0, 64); + } + + par->red[regno] = (u8) red; + par->green[regno] = (u8) green; + par->blue[regno] = (u8) blue; + + if (regno < 32) { + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, + (u8) red, par->green[regno*2], + (u8) blue, mmio); + } + for (i = 0; i < 4; i++) + i810_write_dac((u8) (regno*4) + i, par->red[regno/2], + (u8) green, par->blue[regno/2], mmio); + } + else { + i810_write_dac((u8) regno, (u8) red, (u8) green, + (u8) blue, mmio); + } + + i810_writeb(PIXCONF1, mmio, temp); + + if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (info->var.green.length == 5) + ((u32 *)info->pseudo_palette)[regno] = + (regno << 10) | (regno << 5) | + regno; + else + ((u32 *)info->pseudo_palette)[regno] = + (regno << 11) | (regno << 5) | + regno; + } + else { + if (info->var.green.length == 5) { + /* RGB 555 */ + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } + else { + /* RGB 565 */ + ((u32 *)info->pseudo_palette)[regno] = + (red & 0xf800) | + ((green & 0xf800) >> 5) | + ((blue & 0xf800) >> 11); + } + } + break; + case 24: /* RGB 888 */ + case 32: /* RGBA 8888 */ + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) + ((u32 *)info->pseudo_palette)[regno] = + (regno << 16) | (regno << 8) | + regno; + else + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + return 0; +} + +static int i810fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 total; + u8 *mmio = par->mmio_start_virtual; + int xoffset = var->xoffset, yoffset = var->yoffset; + + if (xoffset < 0 || + xoffset+var->xres > var->xres_virtual || + yoffset < 0 || + yoffset+var->yres > var->yres_virtual) + return -EINVAL; + + total = xoffset * par->depth + yoffset * info->fix.line_length; + i810_writel(DPLYBASE, mmio, par->fb.physical + total); + + return 0; +} + +static int i810fb_blank (int blank_mode, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 *mmio = par->mmio_start_virtual; + int mode = 0, pwr, scr_off = 0; + + pwr = i810_readl(PWR_CLKC, mmio); + + switch(blank_mode) { + case VESA_NO_BLANKING: + mode = POWERON; + pwr |= 1; + scr_off = ON; + break; + case VESA_VSYNC_SUSPEND: + mode = STANDBY; + pwr |= 1; + scr_off = OFF; + break; + case VESA_HSYNC_SUSPEND: + mode = SUSPEND; + pwr |= 1; + scr_off = OFF; + break; + case VESA_POWERDOWN: + mode = POWERDOWN; + pwr &= ~1; + scr_off = OFF; + break; + default: + return -EINVAL; + } + i810_screen_off(mmio, scr_off); + i810_writel(HVSYNC, mmio, mode); + i810_writel(PWR_CLKC, mmio, pwr); + return 0; +} + +static int i810fb_set_par(struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + i810_load_regs(par); + i810_init_cursor(par); + par->cursor_reset = 1; + encode_fix(&info->fix, info); + + return 0; +} + +static int i810fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + int err; + + if (IS_DVT) { + var->vmode &= ~FB_VMODE_MASK; + var->vmode |= FB_VMODE_NONINTERLACED; + } + if (var->vmode & FB_VMODE_DOUBLE) { + var->vmode &= ~FB_VMODE_MASK; + var->vmode |= FB_VMODE_NONINTERLACED; + } + + i810_round_off(var); + if ((err = i810_check_params(var, info))) + return err; + + i810fb_fill_var_timings(var); + set_color_bitfields(var); + decode_var(&info->var, par, info); + return 0; +} + +static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + static u8 data[64 * 8]; + struct i810fb_par *par = (struct i810fb_par *)info->par; + u8 *mmio = par->mmio_start_virtual; + u16 flags = cursor->set; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP) { + return soft_cursor(info, cursor); + } + + if (cursor->image.width > 64 || cursor->image.height > 64 || + (cursor->dest == NULL && cursor->rop == ROP_XOR)) + return 1; + + if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) { + i810_init_cursor(par); + par->cursor_reset = 1; + } + + if (par->cursor_reset) { + flags = FB_CUR_SETALL; + par->cursor_reset = 0; + } + + i810_enable_cursor(mmio, OFF); + + if (flags & FB_CUR_SETPOS) { + u32 tmp; + + tmp = cursor->image.dx - info->var.xoffset; + tmp |= (cursor->image.dy - info->var.yoffset) << 16; + + i810_writel(CURPOS, mmio, tmp); + } + + if (flags & FB_CUR_SETSIZE) { + i810_reset_cursor_image(par); + } + + if (flags & FB_CUR_SETCMAP) { + i810_load_cursor_colors(cursor->image.fg_color, + cursor->image.bg_color, + info); + } + + if (flags & (FB_CUR_SETDEST | FB_CUR_SETSHAPE)) { + int size = ((cursor->image.width + 7)/8) * + cursor->image.height; + int i; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < size; i++) { + data[i] = (cursor->image.data[i] & + cursor->mask[i]) ^ + cursor->dest[i]; + } + break; + case ROP_COPY: + default: + for (i = 0; i < size; i++) { + data[i] = cursor->image.data[i] & + cursor->mask[i]; + } + break; + } + i810_load_cursor_image(cursor->image.width, + cursor->image.height, data, + par); + } + + if (cursor->enable) + i810_enable_cursor(mmio, ON); + + return 0; +} + +static struct fb_ops i810fb_ops __initdata = { + .owner = THIS_MODULE, + .fb_open = i810fb_open, + .fb_release = i810fb_release, + .fb_check_var = i810fb_check_var, + .fb_set_par = i810fb_set_par, + .fb_setcolreg = i810fb_setcolreg, + .fb_blank = i810fb_blank, + .fb_pan_display = i810fb_pan_display, + .fb_fillrect = i810fb_fillrect, + .fb_copyarea = i810fb_copyarea, + .fb_imageblit = i810fb_imageblit, + .fb_cursor = i810fb_cursor, +}; + +/*********************************************************************** + * AGP resource allocation * + ***********************************************************************/ + +static void __devinit i810_fix_pointers(struct i810fb_par *par) +{ + par->fb.physical = par->aperture.physical+(par->fb.offset << 12); + par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12); + par->iring.physical = par->aperture.physical + + (par->iring.offset << 12); + par->iring.virtual = par->aperture.virtual + + (par->iring.offset << 12); + par->cursor_heap.virtual = par->aperture.virtual+ + (par->cursor_heap.offset << 12); + par->pixmap.virtual = par->aperture.virtual + + (par->pixmap.offset << 12); + par->pixmap.physical = par->aperture.physical + + (par->pixmap.offset << 12); +} + +static void __devinit i810_fix_offsets(struct i810fb_par *par) +{ + if (vram + 1 > par->aperture.size >> 20) + vram = (par->aperture.size >> 20) - 1; + if (v_offset_default > (par->aperture.size >> 20)) + v_offset_default = (par->aperture.size >> 20); + if (vram + v_offset_default + 1 > par->aperture.size >> 20) + v_offset_default = (par->aperture.size >> 20) - (vram + 1); + + par->fb.size = vram << 20; + par->fb.offset = v_offset_default << 20; + par->fb.offset >>= 12; + + par->iring.offset = par->fb.offset + (par->fb.size >> 12); + par->iring.size = RINGBUFFER_SIZE; + + par->pixmap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12); + par->pixmap.size = PIXMAP_SIZE; + + par->cursor_heap.offset = par->pixmap.offset + (PIXMAP_SIZE >> 12); + par->cursor_heap.size = 4096; +} + +static int __devinit i810_alloc_agp_mem(struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + int size; + + i810_fix_offsets(par); + size = par->fb.size + par->iring.size + par->pixmap.size; + + par->drm_agp = (drm_agp_t *) inter_module_get("drm_agp"); + if (!par->drm_agp) { + printk("i810fb: cannot acquire agp\n"); + return -ENODEV; + } + par->drm_agp->acquire(); + + if (!(par->i810_gtt.i810_fb_memory = + par->drm_agp->allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) { + printk("i810fb_alloc_fbmem: can't allocate framebuffer " + "memory\n"); + par->drm_agp->release(); + return -ENOMEM; + } + if (par->drm_agp->bind_memory(par->i810_gtt.i810_fb_memory, + par->fb.offset)) { + printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n"); + par->drm_agp->release(); + return -EBUSY; + } + + if (!(par->i810_gtt.i810_cursor_memory = + par->drm_agp->allocate_memory(par->cursor_heap.size >> 12, + AGP_PHYSICAL_MEMORY))) { + printk("i810fb_alloc_cursormem: can't allocate" + "cursor memory\n"); + par->drm_agp->release(); + return -ENOMEM; + } + if (par->drm_agp->bind_memory(par->i810_gtt.i810_cursor_memory, + par->cursor_heap.offset)) { + printk("i810fb_alloc_cursormem: cannot bind cursor memory\n"); + par->drm_agp->release(); + return -EBUSY; + } + + par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical; + + i810_fix_pointers(par); + + par->drm_agp->release(); + + return 0; +} + +/*************************************************************** + * Initialization * + ***************************************************************/ + +/** + * i810_init_monspecs + * @info: pointer to device specific info structure + * + * DESCRIPTION: + * Sets the the user monitor's horizontal and vertical + * frequency limits + */ +static void __devinit i810_init_monspecs(struct fb_info *info) +{ + if (!hsync1) + hsync1 = HFMIN; + if (!hsync2) + hsync2 = HFMAX; + info->monspecs.hfmax = hsync2; + info->monspecs.hfmin = hsync1; + if (hsync2 < hsync1) + info->monspecs.hfmin = hsync2; + + if (!vsync1) + vsync1 = VFMIN; + if (!vsync2) + vsync2 = VFMAX; + if (IS_DVT && vsync1 < 60) + vsync1 = 60; + info->monspecs.vfmax = vsync2; + info->monspecs.vfmin = vsync1; + if (vsync2 < vsync1) + info->monspecs.vfmin = vsync2; +} + +/** + * i810_init_defaults - initializes default values to use + * @par: pointer to i810fb_par structure + * @info: pointer to current fb_info structure + */ +static void __devinit i810_init_defaults(struct i810fb_par *par, + struct fb_info *info) +{ + if (voffset) { + v_offset_default = voffset; + } + else { + if (par->aperture.size > 32 * 1024 * 1024) + v_offset_default = 16; + else + v_offset_default = 8; + } + + if (!vram) + vram = 1; + + if (accel) + par->dev_flags |= HAS_ACCELERATION; + + if (sync) + par->dev_flags |= ALWAYS_SYNC; + + if (bpp < 8) + bpp = 8; + + if (!vyres) + vyres = (vram << 20)/(xres*bpp >> 3); + + par->i810fb_ops = i810fb_ops; + i810fb_default.xres = xres; + i810fb_default.yres = yres; + i810fb_default.yres_virtual = vyres; + i810fb_default.bits_per_pixel = bpp; + + if (dcolor) + i810fb_default.nonstd = 1; + + if (par->dev_flags & HAS_ACCELERATION) + i810fb_default.accel_flags = 1; + + i810_init_monspecs(info); +} + +/** + * i810_init_device - initialize device + * @par: pointer to i810fb_par structure + */ +static void __devinit i810_init_device(struct i810fb_par *par) +{ + u8 reg, *mmio = par->mmio_start_virtual; + + if (mtrr) set_mtrr(par); + + i810_init_cursor(par); + + /* mvo: enable external vga-connector (for laptops) */ + if (ext_vga) { + i810_writel(HVSYNC, mmio, 0); + i810_writel(PWR_CLKC, mmio, 3); + } + + pci_read_config_byte(par->dev, 0x50, ®); + reg &= FREQ_MASK; + par->mem_freq = (reg) ? 133 : 100; + + i810fb_init_ringbuffer(par); +} + +static int __devinit +i810_allocate_pci_resource(struct i810fb_par *par, + const struct pci_device_id *entry) +{ + int err; + + if ((err = pci_enable_device(par->dev))) { + printk("i810fb_init: cannot enable device\n"); + return err; + } + par->res_flags |= PCI_DEVICE_ENABLED; + + if (pci_resource_len(par->dev, 0) > 512 * 1024) { + par->aperture.physical = pci_resource_start(par->dev, 0); + par->aperture.size = pci_resource_len(par->dev, 0); + par->mmio_start_phys = pci_resource_start(par->dev, 1); + } + else { + par->aperture.physical = pci_resource_start(par->dev, 1); + par->aperture.size = pci_resource_len(par->dev, 1); + par->mmio_start_phys = pci_resource_start(par->dev, 0); + } + if (!par->aperture.size) { + printk("i810fb_init: device is disabled\n"); + return -ENOMEM; + } + + if (!request_mem_region(par->aperture.physical, + par->aperture.size, + i810_pci_list[entry->driver_data])) { + printk("i810fb_init: cannot request framebuffer region\n"); + return -ENODEV; + } + par->res_flags |= FRAMEBUFFER_REQ; + + par->aperture.virtual = ioremap(par->aperture.physical, + par->aperture.size); + if (!par->aperture.virtual) { + printk("i810fb_init: cannot remap framebuffer region\n"); + return -ENODEV; + } + + if (!request_mem_region(par->mmio_start_phys, + MMIO_SIZE, + i810_pci_list[entry->driver_data])) { + printk("i810fb_init: cannot request mmio region\n"); + return -ENODEV; + } + par->res_flags |= MMIO_REQ; + + par->mmio_start_virtual = ioremap_nocache(par->mmio_start_phys, + MMIO_SIZE); + if (!par->mmio_start_virtual) { + printk("i810fb_init: cannot remap mmio region\n"); + return -ENODEV; + } + + return 0; +} + +int __init i810fb_setup(char *options) +{ + char *this_opt, *suffix = NULL; + + i810_init = 1; + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "mtrr", 4)) + mtrr = 1; + else if (!strncmp(this_opt, "accel", 5)) + accel = 1; + else if (!strncmp(this_opt, "ext_vga", 7)) + ext_vga = 1; + else if (!strncmp(this_opt, "sync", 4)) + sync = 1; + else if (!strncmp(this_opt, "vram:", 5)) + vram = (simple_strtoul(this_opt+5, NULL, 0)); + else if (!strncmp(this_opt, "voffset:", 8)) + voffset = (simple_strtoul(this_opt+8, NULL, 0)); + else if (!strncmp(this_opt, "xres:", 5)) + xres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "yres:", 5)) + yres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vyres:", 6)) + vyres = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "bpp:", 4)) + bpp = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "hsync1:", 7)) { + hsync1 = simple_strtoul(this_opt+7, &suffix, 0); + if (strncmp(suffix, "H", 1)) + hsync1 *= 1000; + } + else if (!strncmp(this_opt, "hsync2:", 7)) { + hsync2 = simple_strtoul(this_opt+7, &suffix, 0); + if (strncmp(suffix, "H", 1)) + hsync2 *= 1000; + } + else if (!strncmp(this_opt, "vsync1:", 7)) + vsync1 = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "vsync2:", 7)) + vsync2 = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "dcolor", 6)) + dcolor = 1; + } + return 0; +} + +static int __devinit i810fb_init_pci (struct pci_dev *dev, + const struct pci_device_id *entry) +{ + struct fb_info *info; + struct i810fb_par *par = NULL; + int err, vfreq, hfreq, pixclock; + + if (!i810_init) + return -EINVAL; + + if (!(info = kmalloc(sizeof(struct fb_info), GFP_KERNEL))) { + i810fb_release_resource(info, par); + return -ENOMEM; + } + memset(info, 0, sizeof(struct fb_info)); + + if(!(par = kmalloc(sizeof(struct i810fb_par), GFP_KERNEL))) { + i810fb_release_resource(info, par); + return -ENOMEM; + } + memset(par, 0, sizeof(struct i810fb_par)); + + par->dev = dev; + info->par = par; + + if ((err = i810_allocate_pci_resource(par, entry))) { + i810fb_release_resource(info, par); + return err; + } + + i810_init_defaults(par, info); + + if ((err = i810_alloc_agp_mem(info))) { + i810fb_release_resource(info, par); + return err; + } + + i810_init_device(par); + + info->screen_base = par->fb.virtual; + info->node = NODEV; + info->fbops = &par->i810fb_ops; + info->pseudo_palette = par->pseudo_palette; + info->flags = FBINFO_FLAG_DEFAULT; + + fb_alloc_cmap(&info->cmap, 256, 0); + + info->var = i810fb_default; + if ((err = info->fbops->fb_check_var(&info->var, info))) { + i810fb_release_resource(info, par); + return err; + } + encode_fix(&info->fix, info); + + err = register_framebuffer(info); + if (err < 0) { + i810fb_release_resource(info, par); + printk("i810fb_init: cannot register framebuffer device\n"); + return err; + } + + pci_set_drvdata(dev, info); + pixclock = 1000000000/(info->var.pixclock); + pixclock *= 1000; + hfreq = pixclock/(info->var.xres + info->var.left_margin + + info->var.hsync_len + info->var.right_margin); + vfreq = hfreq/(info->var.yres + info->var.upper_margin + + info->var.vsync_len + info->var.lower_margin); + printk("fb: %s v%d.%d.%d%s, Tony Daplas\n" + " Video RAM : %dK\n" + " Mode : %dx%d-%dbpp@%dHz\n" + " Acceleration : %sabled\n" + " MTRR : %sabled\n" + " External VGA : %sabled\n" + " Video Timings : %s\n", + i810_pci_list[entry->driver_data], + VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION, + (int) par->fb.size>>10, info->var.xres, + info->var.yres, info->var.bits_per_pixel, vfreq, + (par->dev_flags & HAS_ACCELERATION) ? "en" : "dis", + (par->dev_flags & HAS_MTRR) ? "en" : "dis", + (ext_vga) ? "en" : "dis", (IS_DVT) ? + "Intel(R) DVT" : "VESA GTF (US)"); + + + return 0; +} + +/*************************************************************** + * Deinitialization * + ***************************************************************/ + +static void i810fb_release_resource(struct fb_info *info, + struct i810fb_par *par) +{ + if (par) { + unset_mtrr(par); + if (par->drm_agp) { + drm_agp_t *agp = par->drm_agp; + struct gtt_data *gtt = &par->i810_gtt; + + if (par->i810_gtt.i810_cursor_memory) + agp->free_memory(gtt->i810_cursor_memory); + if (par->i810_gtt.i810_fb_memory) + agp->free_memory(gtt->i810_fb_memory); + + inter_module_put("drm_agp"); + par->drm_agp = NULL; + } + + if (par->mmio_start_virtual) + iounmap(par->mmio_start_virtual); + if (par->aperture.virtual) + iounmap(par->aperture.virtual); + + if (par->res_flags & FRAMEBUFFER_REQ) + release_mem_region(par->aperture.physical, + par->aperture.size); + if (par->res_flags & MMIO_REQ) + release_mem_region(par->mmio_start_phys, MMIO_SIZE); + + if (par->res_flags & PCI_DEVICE_ENABLED) + pci_disable_device(par->dev); + + kfree(par); + } + if (info) + kfree(info); +} + +static void __devexit i810fb_remove_pci(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = (struct i810fb_par *) info->par; + + unregister_framebuffer(info); + i810fb_release_resource(info, par); + pci_set_drvdata(dev, NULL); + printk("cleanup_module: unloaded i810 framebuffer device\n"); +} + +#ifndef MODULE +int __init i810fb_init(void) +{ + if (agp_init()) { + printk("i810fb_init: cannot initialize agpgart\n"); + return -ENODEV; + } + + if (agp_intel_init()) { + printk("i810fb_init: cannot initialize intel agpgart\n"); + return -ENODEV; + } + + return (pci_module_init(&i810fb_driver)); +} +#endif + +/********************************************************************* + * Modularization * + *********************************************************************/ + +#ifdef MODULE + +int __init i810fb_init(void) +{ + i810_init = 1; + hsync1 *= 1000; + hsync2 *= 1000; + + return (pci_module_init(&i810fb_driver)); +} + +MODULE_PARM(vram, "i"); +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" + " (default=4)"); +MODULE_PARM(voffset, "i"); +MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer " + "memory (0 to maximum aperture size), in MiB (default = 48)"); +MODULE_PARM(bpp, "i"); +MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel" + " (default = 8)"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Hozizontal resolution in pixels (default = 640)"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)"); +MODULE_PARM(vyres, "i"); +MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines" + " (default = 480)"); +MODULE_PARM(hsync1, "i"); +MODULE_PARM_DESC(hsync1, "Mimimum horizontal frequency of monitor in KHz" + " (default = 31)"); +MODULE_PARM(hsync2, "i"); +MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz" + " (default = 31)"); +MODULE_PARM(vsync1, "i"); +MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz" + " (default = 50)"); +MODULE_PARM(vsync2, "i"); +MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" + " (default = 60)"); +MODULE_PARM(accel, "i"); +MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); +MODULE_PARM(mtrr, "i"); +MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)"); +MODULE_PARM(ext_vga, "i"); +MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)"); +MODULE_PARM(sync, "i"); +MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" + " (default = 0)"); +MODULE_PARM(dcolor, "i"); +MODULE_PARM_DESC(dcolor, "use DirectColor visuals" + " (default = 0 = TrueColor)"); + +MODULE_AUTHOR("Tony A. Daplas"); +MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" + " compatible cards"); +MODULE_LICENSE("GPL"); + +static void __exit i810fb_exit(void) +{ + pci_unregister_driver(&i810fb_driver); +} +module_init(i810fb_init); +module_exit(i810fb_exit); + +#endif /* MODULE */ + + diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h new file mode 100644 index 000000000000..cbc80aa11e0b --- /dev/null +++ b/drivers/video/i810/i810_main.h @@ -0,0 +1,205 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810fb_main.h -- Intel 810 frame buffer device + * main header file + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __I810_MAIN_H__ +#define __I810_MAIN_H__ + + +/* PCI */ +static const char *i810_pci_list[] __devinitdata = { + "Intel(R) 810 Framebuffer Device" , + "Intel(R) 810-DC100 Framebuffer Device" , + "Intel(R) 810E Framebuffer Device" , + "Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device" , + "Intel(R) 815 (Internal Graphics only) Framebuffer Device" , + "Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device" +}; + +static struct pci_device_id i810fb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + /* mvo: added i815 PCI-ID */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 } +}; + +static int __devinit i810fb_init_pci (struct pci_dev *dev, + const struct pci_device_id *entry); +static void __devexit i810fb_remove_pci(struct pci_dev *dev); + +static struct pci_driver i810fb_driver = { + .name = "i810fb", + .id_table = i810fb_pci_tbl, + .probe = i810fb_init_pci, + .remove = __devexit_p(i810fb_remove_pci), +}; + +static int i810_init __devinitdata = 0; +static int vram __devinitdata = 4; +static int bpp __devinitdata = 8; +static int mtrr __devinitdata = 0; +static int accel __devinitdata = 0; +static int hsync1 __devinitdata = 0; +static int hsync2 __devinitdata = 0; +static int vsync1 __devinitdata = 0; +static int vsync2 __devinitdata = 0; +static int xres __devinitdata = 640; +static int yres __devinitdata = 480; +static int vyres __devinitdata = 0; +static int sync __devinitdata = 0; +static int ext_vga __devinitdata = 0; +static int dcolor __devinitdata = 0; + +/* "use once" vars */ +static char i810fb_name[16] = "i810fb"; +static struct fb_var_screeninfo i810fb_default __devinitdata = { + /* 640x480, 8 bpp */ + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 8, + .grayscale = 0, + .red = {0, 8, 0}, + .green = {0, 8, 0}, + .blue = {0, 8, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = 0, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* + * voffset - framebuffer offset in MiB from aperture start address. In order for + * the driver to work with X, we must try to use memory holes left untouched by X. The + * following table lists where X's different surfaces start at. + * + * --------------------------------------------- + * : : 64 MiB : 32 MiB : + * ---------------------------------------------- + * : FrontBuffer : 0 : 0 : + * : DepthBuffer : 48 : 16 : + * : BackBuffer : 56 : 24 : + * ---------------------------------------------- + * + * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to + * 15 + 1 MiB of Framebuffer memory. For 32 MiB Aperture sizes, a v_offset of 8 MiB should + * work, allowing 7 + 1 MiB of Framebuffer memory. + * Note, the size of the hole may change depending on how much memory you allocate to X, + * and how the memory is split up between these surfaces. + * + * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with + * DRI disabled. But if the Frontbuffer is overlapped, X will fail to load. + * + * Experiment with v_offset to find out which works best for you. + */ +static u32 v_offset_default __devinitdata; /* For 32 MiB Aper size, 8 should be the default */ +static u32 voffset __devinitdata = 0; + +static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor); + +/* Chipset Specific Functions */ +static int i810fb_set_par (struct fb_info *info); +static int i810fb_getcolreg (u8 regno, u8 *red, u8 *green, u8 *blue, + u8 *transp, struct fb_info *info); +static int i810fb_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info); +static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +static int i810fb_blank (int blank_mode, struct fb_info *info); + +/* Initialization */ +static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par); +extern int __init agp_intel_init(void); +extern int __init agp_init(void); + + +/* Video Timings */ +extern void round_off_xres (u32 *xres); +extern void round_off_yres (u32 *xres, u32 *yres); +extern u32 i810_get_watermark (const struct fb_var_screeninfo *var, + struct i810fb_par *par); +extern void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres); +extern void i810fb_fill_var_timings(struct fb_var_screeninfo *var); + +/* Accelerated Functions */ +extern void i810fb_fillrect (struct fb_info *p, struct fb_fillrect *rect); +extern void i810fb_copyarea (struct fb_info *p, struct fb_copyarea *region); +extern void i810fb_imageblit(struct fb_info *p, struct fb_image *image); +extern int i810fb_sync (struct fb_info *p); + +extern void i810fb_init_ringbuffer (struct i810fb_par *par); + +/* Conditionals */ +#if defined(__i386__) +inline void flush_cache(void) +{ + asm volatile ("wbinvd":::"memory"); +} +#else +#define flush_cache() do { } while(0) +#endif + +#ifdef CONFIG_MTRR +#define KERNEL_HAS_MTRR 1 +static inline void __devinit set_mtrr(struct i810fb_par *par) +{ + par->mtrr_reg = mtrr_add((u32) par->aperture.physical, + par->aperture.size, MTRR_TYPE_WRCOMB, 1); + if (par->mtrr_reg < 0) { + printk("set_mtrr: unable to set MTRR/n"); + return; + } + par->dev_flags |= HAS_MTRR; +} +static inline void unset_mtrr(struct i810fb_par *par) +{ + if (par->dev_flags & HAS_MTRR) + mtrr_del(par->mtrr_reg, (u32) par->aperture.physical, + par->aperture.size); +} +#else +#define KERNEL_HAS_MTRR 0 +#define set_mtrr(x) printk("set_mtrr: MTRR is disabled in the kernel\n") + +#define unset_mtrr(x) do { } while (0) +#endif /* CONFIG_MTRR */ + +#ifdef CONFIG_FB_I810_GTF +#define IS_DVT (0) +#else +#define IS_DVT (1) +#endif + +#endif /* __I810_MAIN_H__ */ diff --git a/drivers/video/i810/i810_regs.h b/drivers/video/i810/i810_regs.h new file mode 100644 index 000000000000..6e4b9afa4d98 --- /dev/null +++ b/drivers/video/i810/i810_regs.h @@ -0,0 +1,274 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_regs.h -- Intel 810/815 Register List + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + + +/* + * Intel 810 Chipset Family PRM 15 3.1 + * GC Register Memory Address Map + * + * Based on: + * Intel (R) 810 Chipset Family + * Programmer s Reference Manual + * November 1999 + * Revision 1.0 + * Order Number: 298026-001 R + * + * All GC registers are memory-mapped. In addition, the VGA and extended VGA registers + * are I/O mapped. + */ + +#ifndef __I810_REGS_H__ +#define __I810_REGS_H__ + +/* Instruction and Interrupt Control Registers (01000h 02FFFh) */ +#define FENCE 0x02000 +#define PGTBL_CTL 0x02020 +#define PGTBL_ER 0x02024 +#define LRING 0x02030 +#define IRING 0x02040 +#define HWS_PGA 0x02080 +#define IPEIR 0x02088 +#define IPEHR 0x0208C +#define INSTDONE 0x02090 +#define NOPID 0x02094 +#define HWSTAM 0x02098 +#define IER 0x020A0 +#define IIR 0x020A4 +#define IMR 0x020A8 +#define ISR 0x020AC +#define EIR 0x020B0 +#define EMR 0x020B4 +#define ESR 0x020B8 +#define INSTPM 0x020C0 +#define INSTPS 0x020C4 +#define BBP_PTR 0x020C8 +#define ABB_SRT 0x020CC +#define ABB_END 0x020D0 +#define DMA_FADD 0x020D4 +#define FW_BLC 0x020D8 +#define MEM_MODE 0x020DC + +/* Memory Control Registers (03000h 03FFFh) */ +#define DRT 0x03000 +#define DRAMCL 0x03001 +#define DRAMCH 0x03002 + + +/* Span Cursor Registers (04000h 04FFFh) */ +#define UI_SC_CTL 0x04008 + +/* I/O Control Registers (05000h 05FFFh) */ +#define HVSYNC 0x05000 +#define GPIOA 0x05010 +#define GPIOB 0x05014 + +/* Clock Control and Power Management Registers (06000h 06FFFh) */ +#define DCLK_0D 0x06000 +#define DCLK_1D 0x06004 +#define DCLK_2D 0x06008 +#define LCD_CLKD 0x0600C +#define DCLK_0DS 0x06010 +#define PWR_CLKC 0x06014 + +/* Graphics Translation Table Range Definition (10000h 1FFFFh) */ +#define GTT 0x10000 + +/* Overlay Registers (30000h 03FFFFh) */ +#define OVOADDR 0x30000 +#define DOVOSTA 0x30008 +#define GAMMA 0x30010 +#define OBUF_0Y 0x30100 +#define OBUF_1Y 0x30104 +#define OBUF_0U 0x30108 +#define OBUF_0V 0x3010C +#define OBUF_1U 0x30110 +#define OBUF_1V 0x30114 +#define OVOSTRIDE 0x30118 +#define YRGB_VPH 0x3011C +#define UV_VPH 0x30120 +#define HORZ_PH 0x30124 +#define INIT_PH 0x30128 +#define DWINPOS 0x3012C +#define DWINSZ 0x30130 +#define SWID 0x30134 +#define SWIDQW 0x30138 +#define SHEIGHT 0x3013F +#define YRGBSCALE 0x30140 +#define UVSCALE 0x30144 +#define OVOCLRCO 0x30148 +#define OVOCLRC1 0x3014C +#define DCLRKV 0x30150 +#define DLCRKM 0x30154 +#define SCLRKVH 0x30158 +#define SCLRKVL 0x3015C +#define SCLRKM 0x30160 +#define OVOCONF 0x30164 +#define OVOCMD 0x30168 +#define AWINPOS 0x30170 +#define AWINZ 0x30174 + +/* BLT Engine Status (40000h 4FFFFh) (Software Debug) */ +#define BR00 0x40000 +#define BRO1 0x40004 +#define BR02 0x40008 +#define BR03 0x4000C +#define BR04 0x40010 +#define BR05 0x40014 +#define BR06 0x40018 +#define BR07 0x4001C +#define BR08 0x40020 +#define BR09 0x40024 +#define BR10 0x40028 +#define BR11 0x4002C +#define BR12 0x40030 +#define BR13 0x40034 +#define BR14 0x40038 +#define BR15 0x4003C +#define BR16 0x40040 +#define BR17 0x40044 +#define BR18 0x40048 +#define BR19 0x4004C +#define SSLADD 0x40074 +#define DSLH 0x40078 +#define DSLRADD 0x4007C + + +/* LCD/TV-Out and HW DVD Registers (60000h 6FFFFh) */ +/* LCD/TV-Out */ +#define HTOTAL 0x60000 +#define HBLANK 0x60004 +#define HSYNC 0x60008 +#define VTOTAL 0x6000C +#define VBLANK 0x60010 +#define VSYNC 0x60014 +#define LCDTV_C 0x60018 +#define OVRACT 0x6001C +#define BCLRPAT 0x60020 + +/* Display and Cursor Control Registers (70000h 7FFFFh) */ +#define DISP_SL 0x70000 +#define DISP_SLC 0x70004 +#define PIXCONF 0x70008 +#define PIXCONF1 0x70009 +#define BLTCNTL 0x7000C +#define SWF 0x70014 +#define DPLYBASE 0x70020 +#define DPLYSTAS 0x70024 +#define CURCNTR 0x70080 +#define CURBASE 0x70084 +#define CURPOS 0x70088 + + +/* VGA Registers */ + +/* SMRAM Registers */ +#define SMRAM 0x10 + +/* Graphics Control Registers */ +#define GR_INDEX 0x3CE +#define GR_DATA 0x3CF + +#define GR10 0x10 +#define GR11 0x11 + +/* CRT Controller Registers */ +#define CR_INDEX_MDA 0x3B4 +#define CR_INDEX_CGA 0x3D4 +#define CR_DATA_MDA 0x3B5 +#define CR_DATA_CGA 0x3D5 + +#define CR30 0x30 +#define CR31 0x31 +#define CR32 0x32 +#define CR33 0x33 +#define CR35 0x35 +#define CR39 0x39 +#define CR40 0x40 +#define CR41 0x41 +#define CR42 0x42 +#define CR70 0x70 +#define CR80 0x80 +#define CR81 0x82 + +/* Extended VGA Registers */ + +/* General Control and Status Registers */ +#define ST00 0x3C2 +#define ST01_MDA 0x3BA +#define ST01_CGA 0x3DA +#define FRC_READ 0x3CA +#define FRC_WRITE_MDA 0x3BA +#define FRC_WRITE_CGA 0x3DA +#define MSR_READ 0x3CC +#define MSR_WRITE 0x3C2 + +/* Sequencer Registers */ +#define SR_INDEX 0x3C4 +#define SR_DATA 0x3C5 + +#define SR01 0x01 +#define SR02 0x02 +#define SR03 0x03 +#define SR04 0x04 +#define SR07 0x07 + +/* Graphics Controller Registers */ +#define GR00 0x00 +#define GR01 0x01 +#define GR02 0x02 +#define GR03 0x03 +#define GR04 0x04 +#define GR05 0x05 +#define GR06 0x06 +#define GR07 0x07 +#define GR08 0x08 + +/* Attribute Controller Registers */ +#define ATTR_WRITE 0x3C0 +#define ATTR_READ 0x3C1 + +/* VGA Color Palette Registers */ + +/* CLUT */ +#define CLUT_DATA 0x3C9 /* DACDATA */ +#define CLUT_INDEX_READ 0x3C7 /* DACRX */ +#define CLUT_INDEX_WRITE 0x3C8 /* DACWX */ +#define DACMASK 0x3C6 + +/* CRT Controller Registers */ +#define CR00 0x00 +#define CR01 0x01 +#define CR02 0x02 +#define CR03 0x03 +#define CR04 0x04 +#define CR05 0x05 +#define CR06 0x06 +#define CR07 0x07 +#define CR08 0x08 +#define CR09 0x09 +#define CR0A 0x0A +#define CR0B 0x0B +#define CR0C 0x0C +#define CR0D 0x0D +#define CR0E 0x0E +#define CR0F 0x0F +#define CR10 0x10 +#define CR11 0x11 +#define CR12 0x12 +#define CR13 0x13 +#define CR14 0x14 +#define CR15 0x15 +#define CR16 0x16 +#define CR17 0x17 +#define CR18 0x18 + +#endif /* __I810_REGS_H__ */ diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index f72ab497c041..4102c3fac1e3 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -75,36 +75,96 @@ struct fb_fix_screeninfo igafb_fix __initdata = { }; struct fb_var_screeninfo default_var = { - /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, - 0, FB_VMODE_NONINTERLACED + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = {0, 8, 0 }, + .green = {0, 8, 0 }, + .blue = {0, 8, 0 }, + .height = -1, + .width = -1, + .accel_flags = FB_ACCEL_NONE, + .pixclock = 39722, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED }; #ifdef __sparc__ struct fb_var_screeninfo default_var_1024x768 __initdata = { - /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ - 1024, 768, 1024, 768, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + .xres = 1024, + .yres = 768, + .xres_virtual = 1024, + .yres_virtual = 768, + .bits_per_pixel = 8, + .red = {0, 8, 0 }, + .green = {0, 8, 0 }, + .blue = {0, 8, 0 }, + .height = -1, + .width = -1, + .accel_flags = FB_ACCEL_NONE, + .pixclock = 12699, + .left_margin = 176, + .right_margin = 16, + .upper_margin = 28, + .lower_margin = 1, + .hsync_len = 96, + .vsync_len = 3, + .vmode = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; struct fb_var_screeninfo default_var_1152x900 __initdata = { - /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */ - 1152, 900, 1152, 900, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */ + .xres = 1152, + .yres = 900, + .xres_virtual = 1152, + .yres_virtual = 900, + .bits_per_pixel = 8, + .red = { 0, 8, 0 }, + .green = { 0, 8, 0 }, + .blue = { 0, 8, 0 }, + .height = -1, + .width = -1, + .accel_flags = FB_ACCEL_NONE, + .pixclock = 9091, + .left_margin = 234, + .right_margin = 24, + .upper_margin = 34, + .lower_margin = 3, + .hsync_len = 100, + .vsync_len = 3, + .vmode = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; struct fb_var_screeninfo default_var_1280x1024 __initdata = { - /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ - 1280, 1024, 1280, 1024, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ + .xres = 1280, + .yres = 1024, + .xres_virtual = 1280, + .yres_virtaul = 1024, + .bits_per_pixel = 8, + .red = {0, 8, 0 }, + .green = {0, 8, 0 }, + .blue = {0, 8, 0 }, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 7408, + .left_margin = 248, + .right_margin = 16, + .upper_margin = 38, + .lower_margin = 1, + .hsync_len = 144, + .vsync_len = 3, + .vmode = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; /* diff --git a/drivers/video/offb.c b/drivers/video/offb.c index f772815444b3..57ecfbeb7471 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -393,6 +393,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct fb_info *info; + int size; if (!request_mem_region(res_start, res_size, "offb")) return; @@ -421,7 +422,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, var = &info->var; strcpy(fix->id, "OFfb "); - strncat(fix->id, name, sizeof(fix->id)); + strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); fix->id[sizeof(fix->id) - 1] = '\0'; var->xres = var->xres_virtual = width; @@ -522,8 +523,6 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->sync = 0; var->vmode = FB_VMODE_NONINTERLACED; - strcpy(fix->id, "OFfb "); - strncat(fix->id, full_name, sizeof(fix->id)); info->node = NODEV; info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); diff --git a/drivers/video/pmagb-b-fb.h b/drivers/video/pmagb-b-fb.h index e93eafa49407..87b81a555139 100644 --- a/drivers/video/pmagb-b-fb.h +++ b/drivers/video/pmagb-b-fb.h @@ -4,7 +4,7 @@ * TurboChannel PMAGB-B framebuffer card support, * Copyright (C) 1999, 2000, 2001 by * Michael Engel <engel@unix-ag.org> and - * Karsten Merker <merker@linxutag.org> + * Karsten Merker <merker@linuxtag.org> * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this * archive for more details. diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index ea8466a9bd7a..75163341953c 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c @@ -361,8 +361,6 @@ struct radeonfb_info { unsigned char *EDID; unsigned char *bios_seg; - struct display disp; /* Will disappear */ - u32 pseudo_palette[17]; struct { u8 red, green, blue, pad; } palette[256]; @@ -1289,7 +1287,7 @@ static int __devinit radeon_init_disp (struct radeonfb_info *rinfo) fb_alloc_cmap(&info->cmap, 256, 0); var.activate = FB_ACTIVATE_NOW; - gen_set_var(&var, -1, info); + fb_set_var(&var, info); return 0; } @@ -1508,7 +1506,7 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg, int con, struct fb_info *info) + unsigned long arg, struct fb_info *info) { struct radeonfb_info *rinfo = (struct radeonfb_info *) info; unsigned int tmp; @@ -1872,14 +1870,26 @@ static int radeonfb_set_par (struct fb_info *info) newmode.crtc_pitch |= (newmode.crtc_pitch << 16); #if defined(__BIG_ENDIAN) - newmode.surface_cntl = SURF_TRANSLATION_DIS; + /* + * It looks like recent chips have a problem with SURFACE_CNTL, + * setting SURF_TRANSLATION_DIS completely disables the + * swapper as well, so we leave it unset now. + */ + newmode.surface_cntl = 0; + + /* Setup swapping on both apertures, though we currently + * only use aperture 0, enabling swapper on aperture 1 + * won't harm + */ switch (mode->bits_per_pixel) { case 16: newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP; + newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP; break; case 24: case 32: newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP; + newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP; break; } #endif @@ -1934,7 +1944,12 @@ static int radeonfb_set_par (struct fb_info *info) newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); } newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; - + +#ifdef CONFIG_ALL_PPC + /* Gross hack for iBook with M7 until I find out a proper fix */ + if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7) + newmode.ppll_div_3 = 0x000600ad; +#endif /* CONFIG_ALL_PPC */ RTRACE("post div = 0x%x\n", rinfo->post_div); RTRACE("fb_div = 0x%x\n", rinfo->fb_div); @@ -2206,12 +2221,8 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) info = &rinfo->info; - // XXX ??? - strncpy (info->modename, rinfo->name, sizeof(info->modename)); - info->currcon = -1; info->par = rinfo; - info->disp = &rinfo->disp; info->pseudo_palette = rinfo->pseudo_palette; info->node = NODEV; info->flags = FBINFO_FLAG_DEFAULT; @@ -2273,7 +2284,12 @@ static int radeon_set_backlight_enable(int on, int level, void *data) unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL); int* conv_table; - if (rinfo->arch == RADEON_M7) + /* Pardon me for that hack... maybe some day we can figure + * out in what direction backlight should work on a given + * panel ? + */ + if ((rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9) + && !machine_is_compatible("PowerBook4,3")) conv_table = backlight_conv_m7; else conv_table = backlight_conv_m6; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 0a44e6dc6a70..67d4c6550d5e 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -50,7 +50,7 @@ #endif /* version number of this driver */ -#define RIVAFB_VERSION "0.9.3" +#define RIVAFB_VERSION "0.9.4" /* ------------------------------------------------------------------------- * * @@ -114,23 +114,43 @@ enum riva_chips { CH_RIVA_128 = 0, CH_RIVA_TNT, CH_RIVA_TNT2, - CH_RIVA_UTNT2, /* UTNT2 */ - CH_RIVA_VTNT2, /* VTNT2 */ - CH_RIVA_UVTNT2, /* VTNT2 */ - CH_RIVA_ITNT2, /* ITNT2 */ + CH_RIVA_UTNT2, + CH_RIVA_VTNT2, + CH_RIVA_UVTNT2, + CH_RIVA_ITNT2, CH_GEFORCE_SDR, CH_GEFORCE_DDR, CH_QUADRO, CH_GEFORCE2_MX, + CH_GEFORCE2_MX2, + CH_GEFORCE2_GO, CH_QUADRO2_MXR, CH_GEFORCE2_GTS, + CH_GEFORCE2_GTS2, CH_GEFORCE2_ULTRA, CH_QUADRO2_PRO, - CH_GEFORCE2_GO, - CH_GEFORCE3, - CH_GEFORCE3_1, - CH_GEFORCE3_2, - CH_QUADRO_DDC + CH_GEFORCE4_MX_460, + CH_GEFORCE4_MX_440, + CH_GEFORCE4_MX_420, + CH_GEFORCE4_440_GO, + CH_GEFORCE4_420_GO, + CH_GEFORCE4_420_GO_M32, + CH_QUADRO4_500XGL, + CH_GEFORCE4_440_GO_M64, + CH_QUADRO4_200, + CH_QUADRO4_550XGL, + CH_QUADRO4_500_GOGL, + CH_IGEFORCE2, + CH_GEFORCE3, + CH_GEFORCE3_1, + CH_GEFORCE3_2, + CH_QUADRO_DDC, + CH_GEFORCE4_TI_4600, + CH_GEFORCE4_TI_4400, + CH_GEFORCE4_TI_4200, + CH_QUADRO4_900XGL, + CH_QUADRO4_750XGL, + CH_QUADRO4_700XGL }; /* directly indexed by riva_chips enum, above */ @@ -149,15 +169,35 @@ static struct riva_chip_info { { "GeForce-DDR", NV_ARCH_10}, { "Quadro", NV_ARCH_10}, { "GeForce2-MX", NV_ARCH_10}, + { "GeForce2-MX", NV_ARCH_10}, + { "GeForce2-Go", NV_ARCH_10}, { "Quadro2-MXR", NV_ARCH_10}, { "GeForce2-GTS", NV_ARCH_10}, + { "GeForce2-GTS", NV_ARCH_10}, { "GeForce2-ULTRA", NV_ARCH_10}, { "Quadro2-PRO", NV_ARCH_10}, - { "GeForce2-Go", NV_ARCH_10}, - { "GeForce3", NV_ARCH_20}, + { "GeForce4-MX-460", NV_ARCH_20 }, + { "GeForce4-MX-440", NV_ARCH_20 }, + { "GeForce4-MX-420", NV_ARCH_20 }, + { "GeForce4-440-GO", NV_ARCH_20 }, + { "GeForce4-420-GO", NV_ARCH_20 }, + { "GeForce4-420-GO-M32", NV_ARCH_20 }, + { "Quadro4-500-XGL", NV_ARCH_20 }, + { "GeForce4-440-GO-M64", NV_ARCH_20 }, + { "Quadro4-200", NV_ARCH_20 }, + { "Quadro4-550-XGL", NV_ARCH_20 }, + { "Quadro4-500-GOGL", NV_ARCH_20 }, + { "GeForce2", NV_ARCH_20 }, + { "GeForce3", NV_ARCH_20}, { "GeForce3 Ti 200", NV_ARCH_20}, { "GeForce3 Ti 500", NV_ARCH_20}, - { "Quadro DDC", NV_ARCH_20} + { "Quadro DDC", NV_ARCH_20}, + { "GeForce4 Ti 4600", NV_ARCH_20 }, + { "GeForce4 Ti 4400", NV_ARCH_20 }, + { "GeForce4 Ti 4200", NV_ARCH_20 }, + { "Quadro4-900-XGL", NV_ARCH_20 }, + { "Quadro4-750-XGL", NV_ARCH_20 }, + { "Quadro4-700-XGL", NV_ARCH_20 } }; static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { @@ -184,56 +224,67 @@ static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX2 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_460 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_440 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_420 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO_M32 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500XGL }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO_M64 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_200 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_550XGL }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500_GOGL }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_IGEFORCE2 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4600 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4400 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4200 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_900XGL }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_750XGL }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_700XGL }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); - - -/* ------------------------------------------------------------------------- * - * - * framebuffer related structures - * - * ------------------------------------------------------------------------- */ - -extern struct display_switch fbcon_riva8; -extern struct display_switch fbcon_riva16; -extern struct display_switch fbcon_riva32; - -struct riva_cursor { - int enable; - int on; - int vbl_cnt; - int last_move_delay; - int blink_rate; - struct { - u16 x, y; - } pos, size; - unsigned short image[MAX_CURS*MAX_CURS]; - struct timer_list *timer; -}; - /* ------------------------------------------------------------------------- * * * global variables @@ -243,7 +294,7 @@ struct riva_cursor { /* command line data, set in rivafb_setup() */ static u32 pseudo_palette[17]; #ifdef CONFIG_MTRR -static char nomtrr __initdata = 0; +static int nomtrr __initdata = 0; #endif #ifndef MODULE @@ -581,6 +632,7 @@ static void riva_load_video_mode(struct fb_info *info) { int bpp, width, hDisplaySize, hDisplay, hStart, hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock; + int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd; struct riva_par *par = (struct riva_par *) info->par; struct riva_regs newmode; @@ -598,7 +650,10 @@ static void riva_load_video_mode(struct fb_info *info) hEnd = (hDisplaySize + info->var.right_margin + info->var.hsync_len) / 8 - 1; hTotal = (hDisplaySize + info->var.right_margin + - info->var.hsync_len + info->var.left_margin) / 8 - 1; + info->var.hsync_len + info->var.left_margin) / 8 - 5; + hBlankStart = hDisplay; + hBlankEnd = hTotal + 4; + height = info->var.yres_virtual; vDisplay = info->var.yres - 1; vStart = info->var.yres + info->var.lower_margin - 1; @@ -606,47 +661,90 @@ static void riva_load_video_mode(struct fb_info *info) info->var.vsync_len - 1; vTotal = info->var.yres + info->var.lower_margin + info->var.vsync_len + info->var.upper_margin + 2; + vBlankStart = vDisplay; + vBlankEnd = vTotal + 1; dotClock = 1000000000 / info->var.pixclock; memcpy(&newmode, ®_template, sizeof(struct riva_regs)); - newmode.crtc[0x0] = Set8Bits (hTotal - 4); + if (par->FlatPanel) { + vStart = vTotal - 3; + vEnd = vTotal - 2; + vBlankStart = vStart; + hStart = hTotal - 3; + hEnd = hTotal - 2; + hBlankEnd = hTotal + 4; + } + + newmode.crtc[0x0] = Set8Bits (hTotal); newmode.crtc[0x1] = Set8Bits (hDisplay); - newmode.crtc[0x2] = Set8Bits (hDisplay); - newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7); + newmode.crtc[0x2] = Set8Bits (hBlankStart); + newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7); newmode.crtc[0x4] = Set8Bits (hStart); - newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7) + newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7) | SetBitField (hEnd, 4: 0, 4:0); newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0); newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0) | SetBitField (vDisplay, 8: 8, 1:1) | SetBitField (vStart, 8: 8, 2:2) - | SetBitField (vDisplay, 8: 8, 3:3) + | SetBitField (vBlankStart, 8: 8, 3:3) | SetBit (4) | SetBitField (vTotal, 9: 9, 5:5) | SetBitField (vDisplay, 9: 9, 6:6) | SetBitField (vStart, 9: 9, 7:7); - newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5) + newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5) | SetBit (6); newmode.crtc[0x10] = Set8Bits (vStart); newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0) | SetBit (5); newmode.crtc[0x12] = Set8Bits (vDisplay); - newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF; - newmode.crtc[0x15] = Set8Bits (vDisplay); - newmode.crtc[0x16] = Set8Bits (vTotal + 1); + newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8); + newmode.crtc[0x15] = Set8Bits (vBlankStart); + newmode.crtc[0x16] = Set8Bits (vBlankEnd); + + newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4) + | SetBitField(vBlankStart,10:10,3:3) + | SetBitField(vStart,10:10,2:2) + | SetBitField(vDisplay,10:10,1:1) + | SetBitField(vTotal,10:10,0:0); + newmode.ext.horiz = SetBitField(hTotal,8:8,0:0) + | SetBitField(hDisplay,8:8,1:1) + | SetBitField(hBlankStart,8:8,2:2) + | SetBitField(hStart,8:8,3:3); + newmode.ext.extra = SetBitField(vTotal,11:11,0:0) + | SetBitField(vDisplay,11:11,2:2) + | SetBitField(vStart,11:11,4:4) + | SetBitField(vBlankStart,11:11,6:6); newmode.ext.bpp = bpp; newmode.ext.width = width; newmode.ext.height = height; + newmode.ext.interlace = 0xff; /* interlace off */ par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width, - hDisplaySize, hDisplay, hStart, hEnd, - hTotal, height, vDisplay, vStart, vEnd, - vTotal, dotClock); + hDisplaySize, height, dotClock); + if (par->SecondCRTC) { + newmode.ext.head = par->riva.PCRTC0[0x00000860/4] & ~0x00001000; + newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] | 0x00001000; + newmode.ext.crtcOwner = 3; + newmode.ext.pllsel |= 0x20000800; + newmode.ext.vpll2 = newmode.ext.vpll; + } else if (par->riva.twoHeads) { + newmode.ext.head = par->riva.PCRTC0[0x00000860/4] | 0x00001000; + newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] & ~0x00001000; + newmode.ext.crtcOwner = 0; + newmode.ext.vpll2 = par->riva.PRAMDAC0[0x00000520/4]; + } + if (par->FlatPanel == 1) { + newmode.ext.pixel |= (1 << 7); + newmode.ext.scale |= (1 << 8) ; + } + newmode.ext.cursorConfig = 0x02000100; par->current_state = newmode; riva_load_state(par, &par->current_state); + par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */ + rivafb_blank(0, info); } /** @@ -916,6 +1014,7 @@ static void rivafb_imageblit(struct fb_info *info, struct fb_image *image) size = width * h; dat = cdat; + for (i = 0; i < size; i++) { *dat = byte_rev[*dat]; dat++; @@ -923,17 +1022,11 @@ static void rivafb_imageblit(struct fb_info *info, struct fb_image *image) switch (info->var.bits_per_pixel) { case 8: - fgx = image->fg_color | ~((1 << 8) - 1); - bgx = image->bg_color | ~((1 << 8) - 1); + fgx = image->fg_color; + bgx = image->bg_color; break; case 16: - /* set alpha bit */ - if (info->var.green.length == 5) { - fgx = 1 << 15; - bgx = fgx; - } - /* Fall through... */ case 32: fgx |= par->riva_palette[image->fg_color]; bgx |= par->riva_palette[image->bg_color]; @@ -1040,7 +1133,7 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) temp = xx & 0xFFFF; temp |= yy << 16; - *(par->riva.CURSORPOS) = temp; + par->riva.PRAMDAC[0x0000300/4] = temp; } if (flags & FB_CUR_SETSIZE) { @@ -1168,7 +1261,10 @@ static int rivafb_open(struct fb_info *info, int user) par->state.flags |= VGA_SAVE_CMAP; save_vga(&par->state); - RivaGetConfig(&par->riva); + RivaGetConfig(&par->riva, par->Chipset); + CRTCout(par, 0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */ + par->riva.LockUnlock(&par->riva, 0); + riva_save_state(par, &par->initial_state); } @@ -1288,7 +1384,6 @@ static int rivafb_set_par(struct fb_info *info) { struct riva_par *par = (struct riva_par *) info->par; - //rivafb_create_cursor(info, fontwidth(dsp), fontheight(dsp)); riva_load_video_mode(info); if (info->var.accel_flags) { riva_setup_accel(par); @@ -1554,13 +1649,14 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) info->display_fg = NULL; info->pseudo_palette = pseudo_palette; - cmap_len = riva_get_cmap_len(&info->var); - fb_alloc_cmap(&info->cmap, cmap_len, 0); #ifndef MODULE if (mode_option) fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); #endif + cmap_len = riva_get_cmap_len(&info->var); + fb_alloc_cmap(&info->cmap, cmap_len, 0); + return 0; } @@ -1693,7 +1789,9 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, strcat(rivafb_fix.id, rci->name); default_par->riva.Architecture = rci->arch_rev; - + default_par->riva.Chipset = pd->device; + + printk(KERN_INFO PFX "nVidia device/chipset %X\n", pd->device); rivafb_fix.mmio_len = pci_resource_len(pd, 0); rivafb_fix.smem_len = pci_resource_len(pd, 1); @@ -1713,13 +1811,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, goto err_out_free_base1; } - info->screen_base = ioremap(rivafb_fix.smem_start, - rivafb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR PFX "cannot ioremap FB base\n"); - goto err_out_iounmap_ctrl; - } - default_par->riva.EnableIRQ = 0; default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000); @@ -1737,13 +1828,30 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, 0x00000000); default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000); - default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000); default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000); default_par->riva.PVIO = (U008 *)(default_par->ctrl_base + 0x000C0000); - default_par->riva.IO = (MISCin(default_par) & 0x01) ? 0x3D0 : 0x3B0; + if (default_par->riva.Architecture == NV_ARCH_03) { + /* + * We have to map the full BASE_1 aperture for Riva128's + * because they use the PRAMIN set in "framebuffer" space + */ + if (!request_mem_region(rivafb_fix.smem_start, + rivafb_fix.smem_len, "rivafb")) { + printk(KERN_ERR PFX "cannot reserve FB region\n"); + goto err_out_free_base0; + } + + info->screen_base = ioremap(rivafb_fix.smem_start, + rivafb_fix.smem_len); + if (!info->screen_base) { + printk(KERN_ERR PFX "cannot ioremap FB base\n"); + goto err_out_iounmap_ctrl; + } + } + switch (default_par->riva.Architecture) { case NV_ARCH_03: default_par->riva.PRAMIN = (unsigned *)(info->screen_base + @@ -1767,17 +1875,23 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, info->par = default_par; - if (!request_mem_region(rivafb_fix.smem_start, - rivafb_fix.smem_len, "rivafb")) { - printk(KERN_ERR PFX "cannot reserve FB region\n"); - goto err_out_free_base0; - } + if (default_par->riva.Architecture != NV_ARCH_03) { + /* + * Now the _normal_ chipsets can just map the amount of + * real physical ram instead of the whole aperture + */ + if (!request_mem_region(rivafb_fix.smem_start, + rivafb_fix.smem_len, "rivafb")) { + printk(KERN_ERR PFX "cannot reserve FB region\n"); + goto err_out_free_base0; + } - info->screen_base = ioremap(rivafb_fix.smem_start, - rivafb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR PFX "cannot ioremap FB base\n"); - goto err_out_iounmap_ctrl; + info->screen_base = ioremap(rivafb_fix.smem_start, + rivafb_fix.smem_len); + if (!info->screen_base) { + printk(KERN_ERR PFX "cannot ioremap FB base\n"); + goto err_out_iounmap_ctrl; + } } #ifdef CONFIG_MTRR diff --git a/drivers/video/riva/nv_type.h b/drivers/video/riva/nv_type.h new file mode 100644 index 000000000000..a69480c9a67c --- /dev/null +++ b/drivers/video/riva/nv_type.h @@ -0,0 +1,58 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_type.h,v 1.35 2002/08/05 20:47:06 mvojkovi Exp $ */ + +#ifndef __NV_STRUCT_H__ +#define __NV_STRUCT_H__ + +#define NV_CHIP_RIVA_128 ((PCI_VENDOR_ID_NVIDIA_SGS << 16)| PCI_DEVICE_ID_NVIDIA_RIVA128) +#define NV_CHIP_TNT ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT) +#define NV_CHIP_TNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT2) +#define NV_CHIP_UTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UTNT2) +#define NV_CHIP_VTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_VTNT2) +#define NV_CHIP_UVTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UVTNT2) +#define NV_CHIP_ITNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_ITNT2) +#define NV_CHIP_GEFORCE_256 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_256) +#define NV_CHIP_GEFORCE_DDR ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR) +#define NV_CHIP_QUADRO ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_QUADRO) +#define NV_CHIP_GEFORCE2_MX ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX) +#define NV_CHIP_GEFORCE2_MX_100 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX_100) +#define NV_CHIP_QUADRO2_MXR ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR) +#define NV_CHIP_GEFORCE2_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO) +#define NV_CHIP_GEFORCE2_GTS ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS) +#define NV_CHIP_GEFORCE2_TI ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_TI) +#define NV_CHIP_GEFORCE2_ULTRA ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA) +#define NV_CHIP_QUADRO2_PRO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO) +#define NV_CHIP_GEFORCE4_MX_460 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460) +#define NV_CHIP_GEFORCE4_MX_440 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440) +#define NV_CHIP_GEFORCE4_MX_420 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420) +#define NV_CHIP_GEFORCE4_440_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO) +#define NV_CHIP_GEFORCE4_420_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO) +#define NV_CHIP_GEFORCE4_420_GO_M32 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32) +#define NV_CHIP_QUADRO4_500XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL) +#define NV_CHIP_GEFORCE4_440_GO_M64 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64) +#define NV_CHIP_QUADRO4_200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_200) +#define NV_CHIP_QUADRO4_550XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL) +#define NV_CHIP_QUADRO4_500_GOGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL) +#define NV_CHIP_0x0180 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0180) +#define NV_CHIP_0x0181 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0181) +#define NV_CHIP_0x0182 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0182) +#define NV_CHIP_0x0188 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0188) +#define NV_CHIP_0x018A ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018A) +#define NV_CHIP_0x018B ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018B) +#define NV_CHIP_IGEFORCE2 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_IGEFORCE2) +#define NV_CHIP_0x01F0 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x01F0) +#define NV_CHIP_GEFORCE3 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3) +#define NV_CHIP_GEFORCE3_TI_200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_200) +#define NV_CHIP_GEFORCE3_TI_500 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_500) +#define NV_CHIP_QUADRO_DCC ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO_DCC) +#define NV_CHIP_GEFORCE4_TI_4600 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600) +#define NV_CHIP_GEFORCE4_TI_4400 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400) +#define NV_CHIP_GEFORCE4_TI_4200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200) +#define NV_CHIP_QUADRO4_900XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL) +#define NV_CHIP_QUADRO4_750XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL) +#define NV_CHIP_QUADRO4_700XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL) +#define NV_CHIP_0x0280 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0280) +#define NV_CHIP_0x0281 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0281) +#define NV_CHIP_0x0288 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0288) +#define NV_CHIP_0x0289 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0289) + +#endif /* __NV_STRUCT_H__ */ diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index ae7da6ed1815..4e840a3a28ec 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c @@ -46,8 +46,12 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.8 2000/02/08 17:19:11 dawes Exp $ */ +#include <linux/pci_ids.h> +#include <linux/pci.h> #include "riva_hw.h" #include "riva_tbl.h" +#include "nv_type.h" + /* * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT * operate identically (except TNT has more memory and better 3D quality. @@ -73,32 +77,39 @@ static int nv10Busy { return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x00000700/4] & 0x01)); } -static void nv3LockUnlock + +static void vgaLockUnlock ( RIVA_HW_INST *chip, - int LockUnlock + int Lock ) { - VGA_WR08(chip->PVIO, 0x3C4, 0x06); - VGA_WR08(chip->PVIO, 0x3C5, LockUnlock ? 0x99 : 0x57); + U008 cr11; + VGA_WR08(chip->PCIO, 0x3D4, 0x11); + cr11 = VGA_RD08(chip->PCIO, 0x3D5); + if(Lock) cr11 |= 0x80; + else cr11 &= ~0x80; + VGA_WR08(chip->PCIO, 0x3D5, cr11); } -static void nv4LockUnlock +static void nv3LockUnlock ( RIVA_HW_INST *chip, - int LockUnlock + int Lock ) { - VGA_WR08(chip->PCIO, 0x3D4, 0x1F); - VGA_WR08(chip->PCIO, 0x3D5, LockUnlock ? 0x99 : 0x57); + VGA_WR08(chip->PVIO, 0x3C4, 0x06); + VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57); + vgaLockUnlock(chip, Lock); } -static void nv10LockUnlock +static void nv4LockUnlock ( RIVA_HW_INST *chip, - int LockUnlock + int Lock ) { VGA_WR08(chip->PCIO, 0x3D4, 0x1F); - VGA_WR08(chip->PCIO, 0x3D5, LockUnlock ? 0x99 : 0x57); + VGA_WR08(chip->PCIO, 0x3D5, Lock ? 0x99 : 0x57); + vgaLockUnlock(chip, Lock); } static int ShowHideCursor @@ -107,13 +118,13 @@ static int ShowHideCursor int ShowHide ) { - int current; - current = chip->CurrentState->cursor1; + int cursor; + cursor = chip->CurrentState->cursor1; chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) | (ShowHide & 0x01); VGA_WR08(chip->PCIO, 0x3D4, 0x31); VGA_WR08(chip->PCIO, 0x3D5, chip->CurrentState->cursor1); - return (current & 0x01); + return (cursor & 0x01); } /****************************************************************************\ @@ -1093,7 +1104,6 @@ static void nv10UpdateArbitrationSettings static int CalcVClock ( int clockIn, - int double_scan, int *clockOut, int *mOut, int *nOut, @@ -1109,18 +1119,16 @@ static int CalcVClock DeltaOld = 0xFFFFFFFF; VClk = (unsigned)clockIn; - if (double_scan) - VClk *= 2; - if (chip->CrystalFreqKHz == 14318) + if (chip->CrystalFreqKHz == 13500) { - lowM = 8; - highM = 14 - (chip->Architecture == NV_ARCH_03); + lowM = 7; + highM = 13 - (chip->Architecture == NV_ARCH_03); } else { - lowM = 7; - highM = 13 - (chip->Architecture == NV_ARCH_03); + lowM = 8; + highM = 14 - (chip->Architecture == NV_ARCH_03); } highP = 4 - (chip->Architecture == NV_ARCH_03); @@ -1131,8 +1139,9 @@ static int CalcVClock { for (M = lowM; M <= highM; M++) { - N = (VClk * M / chip->CrystalFreqKHz) << P; - Freq = (chip->CrystalFreqKHz * N / M) >> P; + N = (VClk << P) * M / chip->CrystalFreqKHz; + if(N <= 255) { + Freq = (chip->CrystalFreqKHz * N / M) >> P; if (Freq > VClk) DeltaNew = Freq - VClk; else @@ -1148,6 +1157,7 @@ static int CalcVClock } } } + } return (DeltaOld != 0xFFFFFFFF); } /* @@ -1161,15 +1171,7 @@ static void CalcStateExt int bpp, int width, int hDisplaySize, - int hDisplay, - int hStart, - int hEnd, - int hTotal, int height, - int vDisplay, - int vStart, - int vEnd, - int vTotal, int dotClock ) { @@ -1184,8 +1186,7 @@ static void CalcStateExt * Extended RIVA registers. */ pixelDepth = (bpp + 1)/8; - CalcVClock(dotClock, hDisplaySize < 512, /* double scan? */ - &VClk, &m, &n, &p, chip); + CalcVClock(dotClock, &VClk, &m, &n, &p, chip); switch (chip->Architecture) { @@ -1225,9 +1226,9 @@ static void CalcStateExt &(state->arbitration0), &(state->arbitration1), chip); - state->cursor0 = 0x00; - state->cursor1 = 0xFC; - state->cursor2 = 0x00000000; + state->cursor0 = 0x00; + state->cursor1 = 0xFC; + state->cursor2 = 0x00000000; state->pllsel = 0x10000700; state->config = chip->PFB[0x00000200/4]; state->general = bpp == 16 ? 0x00101100 : 0x00100100; @@ -1235,13 +1236,7 @@ static void CalcStateExt break; } state->vpll = (p << 16) | (n << 8) | m; - state->screen = ((hTotal & 0x040) >> 2) - | ((vDisplay & 0x400) >> 7) - | ((vStart & 0x400) >> 8) - | ((vDisplay & 0x400) >> 9) - | ((vTotal & 0x400) >> 10); state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3; - state->horiz = hTotal < 260 ? 0x00 : 0x01; state->pixel = pixelDepth > 2 ? 3 : pixelDepth; state->offset0 = state->offset1 = @@ -1285,6 +1280,7 @@ static void UpdateFifoState chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); break; case NV_ARCH_10: + case NV_ARCH_20: /* * Initialize state for the RivaTriangle3D05 routines. */ @@ -1503,7 +1499,7 @@ static void LoadStateExt chip->PGRAPH[0x00000F50/4] = 0x00000040; for (i = 0; i < 4; i++) chip->PGRAPH[0x00000F54/4] = 0x00000000; - break; + break; } LOAD_FIXED_STATE(Riva,FIFO); UpdateFifoState(chip); @@ -1532,11 +1528,12 @@ static void LoadStateExt chip->PRAMDAC[0x00000508/4] = state->vpll; chip->PRAMDAC[0x0000050C/4] = state->pllsel; chip->PRAMDAC[0x00000600/4] = state->general; + /* * Turn off VBlank enable and reset. */ - *(chip->VBLANKENABLE) = 0; - *(chip->VBLANK) = chip->VBlankBit; + chip->PCRTC[0x00000140/4] = 0; + chip->PCRTC[0x00000100/4] = chip->VBlankBit; /* * Set interrupt enable. */ @@ -1806,9 +1803,6 @@ static void nv3GetConfig } chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000020) ? 14318 : 13500; chip->CURSOR = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]); - chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); - chip->VBLANKENABLE = &(chip->PGRAPH[0x0140/4]); - chip->VBLANK = &(chip->PGRAPH[0x0100/4]); chip->VBlankBit = 0x00000100; chip->MaxVClockFreqKHz = 256000; /* @@ -1867,9 +1861,6 @@ static void nv4GetConfig } chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500; chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]); - chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); - chip->VBLANKENABLE = &(chip->PCRTC[0x0140/4]); - chip->VBLANK = &(chip->PCRTC[0x0100/4]); chip->VBlankBit = 0x00000001; chip->MaxVClockFreqKHz = 350000; /* @@ -1887,12 +1878,30 @@ static void nv4GetConfig } static void nv10GetConfig ( - RIVA_HW_INST *chip + RIVA_HW_INST *chip, + unsigned int chipset ) { + struct pci_dev* dev; + int amt; + +#ifdef __BIG_ENDIAN + /* turn on big endian register access */ + chip->PMC[0x00000004/4] = 0x01000001; +#endif + /* * Fill in chip configuration. */ + if(chipset == NV_CHIP_IGEFORCE2) { + dev = pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x7C, &amt); + chip->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; + } else if(chipset == NV_CHIP_0x01F0) { + dev = pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x84, &amt); + chip->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; + } else { switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) { case 0x02: @@ -1920,6 +1929,7 @@ static void nv10GetConfig chip->RamAmountKBytes = 1024 * 16; break; } + } switch ((chip->PFB[0x00000000/4] >> 3) & 0x00000003) { case 3: @@ -1931,9 +1941,6 @@ static void nv10GetConfig } chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500; chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]); - chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); - chip->VBLANKENABLE = &(chip->PCRTC[0x0140/4]); - chip->VBLANK = &(chip->PCRTC[0x0100/4]); chip->VBlankBit = 0x00000001; chip->MaxVClockFreqKHz = 350000; /* @@ -1947,11 +1954,12 @@ static void nv10GetConfig chip->SetStartAddress = SetStartAddress; chip->SetSurfaces2D = nv10SetSurfaces2D; chip->SetSurfaces3D = nv10SetSurfaces3D; - chip->LockUnlock = nv10LockUnlock; + chip->LockUnlock = nv4LockUnlock; } int RivaGetConfig ( - RIVA_HW_INST *chip + RIVA_HW_INST *chip, + unsigned int chipset ) { /* @@ -1970,11 +1978,13 @@ int RivaGetConfig nv4GetConfig(chip); break; case NV_ARCH_10: - nv10GetConfig(chip); + case NV_ARCH_20: + nv10GetConfig(chip, chipset); break; default: return (-1); } + chip->Chipset = chipset; /* * Fill in FIFO pointers. */ diff --git a/drivers/video/riva/riva_hw.h b/drivers/video/riva/riva_hw.h index 22d056b0fd2e..e54b015bd529 100644 --- a/drivers/video/riva/riva_hw.h +++ b/drivers/video/riva/riva_hw.h @@ -44,11 +44,25 @@ * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.6 2000/02/08 17:19:12 dawes Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.21 2002/10/14 18:22:46 mvojkovi Exp $ */ #ifndef __RIVA_HW_H__ #define __RIVA_HW_H__ #define RIVA_SW_VERSION 0x00010003 +#ifndef Bool +typedef int Bool; +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + /* * Typedefs to force certain sized values. */ @@ -59,8 +73,14 @@ typedef unsigned int U032; /* * HW access macros. */ +#if defined(__powerpc__) +#include <asm/io.h> +#define NV_WR08(p,i,d) out_8(p+i, d) +#define NV_RD08(p,i) in_8(p+i) +#else #define NV_WR08(p,i,d) (((U008 *)(p))[i]=(d)) #define NV_RD08(p,i) (((U008 *)(p))[i]) +#endif #define NV_WR16(p,i,d) (((U016 *)(p))[(i)/2]=(d)) #define NV_RD16(p,i) (((U016 *)(p))[(i)/2]) #define NV_WR32(p,i,d) (((U032 *)(p))[(i)/4]=(d)) @@ -75,6 +95,7 @@ typedef unsigned int U032; #define NV_ARCH_04 0x04 #define NV_ARCH_10 0x10 #define NV_ARCH_20 0x20 + /***************************************************************************\ * * * FIFO registers. * @@ -87,8 +108,12 @@ typedef unsigned int U032; typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BB]; U032 Rop3; } RivaRop; @@ -98,8 +123,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BD]; U032 Shape; U032 reserved03[0x001]; @@ -113,8 +142,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BB]; U032 TopLeft; U032 WidthHeight; @@ -125,8 +158,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop[1]; +#endif U032 reserved01[0x0BC]; U032 Color; U032 reserved03[0x03E]; @@ -139,8 +176,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BB]; U032 TopLeftSrc; U032 TopLeftDst; @@ -152,8 +193,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop[1]; +#endif U032 reserved01[0x0BC]; U032 TopLeft; U032 WidthHeight; @@ -167,8 +212,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BB]; U032 reserved03[(0x040)-1]; U032 Color1A; @@ -229,8 +278,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BC]; U032 TextureOffset; U032 TextureFormat; @@ -255,8 +308,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BB]; U032 ColorKey; U032 TextureOffset; @@ -289,8 +346,12 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop[1]; +#endif U032 reserved01[0x0BC]; U032 Color; /* source color 0304-0307*/ U032 Reserved02[0x03e]; @@ -320,16 +381,24 @@ typedef volatile struct typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BE]; U032 Offset; } RivaSurface; typedef volatile struct { U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else U016 FifoFree; U016 Nop; +#endif U032 reserved01[0x0BD]; U032 Pitch; U032 RenderBufferOffset; @@ -342,6 +411,9 @@ typedef volatile struct * * \***************************************************************************/ +#define FP_ENABLE 1 +#define FP_DITHER 2 + struct _riva_hw_inst; struct _riva_hw_state; /* @@ -354,6 +426,7 @@ typedef struct _riva_hw_inst */ U032 Architecture; U032 Version; + U032 Chipset; U032 CrystalFreqKHz; U032 RamAmountKBytes; U032 MaxVClockFreqKHz; @@ -363,11 +436,15 @@ typedef struct _riva_hw_inst U032 VBlankBit; U032 FifoFreeCount; U032 FifoEmptyCount; + U032 CursorStart; + U032 flatPanel; + Bool twoHeads; /* * Non-FIFO registers. */ + volatile U032 *PCRTC0; volatile U032 *PCRTC; - volatile U032 *PRAMDAC; + volatile U032 *PRAMDAC0; volatile U032 *PFB; volatile U032 *PFIFO; volatile U032 *PGRAPH; @@ -377,17 +454,17 @@ typedef struct _riva_hw_inst volatile U032 *PRAMIN; volatile U032 *FIFO; volatile U032 *CURSOR; - volatile U032 *CURSORPOS; - volatile U032 *VBLANKENABLE; - volatile U032 *VBLANK; + volatile U008 *PCIO0; volatile U008 *PCIO; volatile U008 *PVIO; + volatile U008 *PDIO0; volatile U008 *PDIO; + volatile U032 *PRAMDAC; /* * Common chip functions. */ int (*Busy)(struct _riva_hw_inst *); - void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int,int,int,int,int,int,int,int,int); + void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int); void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *); void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *); void (*SetStartAddress)(struct _riva_hw_inst *,U032); @@ -420,17 +497,26 @@ typedef struct _riva_hw_state U032 bpp; U032 width; U032 height; + U032 interlace; U032 repaint0; U032 repaint1; U032 screen; + U032 scale; + U032 dither; + U032 extra; U032 pixel; U032 horiz; U032 arbitration0; U032 arbitration1; U032 vpll; + U032 vpll2; U032 pllsel; U032 general; + U032 crtcOwner; + U032 head; + U032 head2; U032 config; + U032 cursorConfig; U032 cursor0; U032 cursor1; U032 cursor2; @@ -446,16 +532,16 @@ typedef struct _riva_hw_state /* * External routines. */ -int RivaGetConfig(RIVA_HW_INST *); +int RivaGetConfig(RIVA_HW_INST *, unsigned int); /* * FIFO Free Count. Should attempt to yield processor if RIVA is busy. */ -#define RIVA_FIFO_FREE(hwinst,hwptr,cnt) \ -{ \ - while ((hwinst).FifoFreeCount < (cnt)) \ - (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2; \ - (hwinst).FifoFreeCount -= (cnt); \ +#define RIVA_FIFO_FREE(hwinst,hwptr,cnt) \ +{ \ + while ((hwinst).FifoFreeCount < (cnt)) \ + (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2; \ + (hwinst).FifoFreeCount -= (cnt); \ } #endif /* __RIVA_HW_H__ */ diff --git a/drivers/video/riva/riva_tbl.h b/drivers/video/riva/riva_tbl.h index 3843ffa73ae4..7ee7d72932d4 100644 --- a/drivers/video/riva/riva_tbl.h +++ b/drivers/video/riva/riva_tbl.h @@ -44,7 +44,9 @@ * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.5 2000/02/08 17:19:12 dawes Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.9 2002/01/30 01:35:03 mvojkovi Exp $ */ + + /* * RIVA Fixed Functionality Init Tables. */ @@ -69,6 +71,7 @@ static unsigned RivaTableFIFO[][2] = {0x00001800, 0x80000010}, {0x00002000, 0x80000011}, {0x00002800, 0x80000012}, + {0x00003000, 0x80000016}, {0x00003800, 0x80000013} }; static unsigned nv3TablePFIFO[][2] = @@ -174,6 +177,8 @@ static unsigned nv3TablePRAMIN[][2] = {0x00000249, 0x00CC0346}, {0x0000024C, 0x80000013}, {0x0000024D, 0x00D70347}, + {0x00000258, 0x80000016}, + {0x00000259, 0x00CA034C}, {0x00000D05, 0x00000000}, {0x00000D06, 0x00000000}, {0x00000D07, 0x00000000}, @@ -210,7 +215,10 @@ static unsigned nv3TablePRAMIN[][2] = {0x00000D2C, 0x10830200}, {0x00000D2D, 0x00000000}, {0x00000D2E, 0x00000000}, - {0x00000D2F, 0x00000000} + {0x00000D2F, 0x00000000}, + {0x00000D31, 0x00000000}, + {0x00000D32, 0x00000000}, + {0x00000D33, 0x00000000} }; static unsigned nv3TablePRAMIN_8BPP[][2] = { @@ -222,7 +230,8 @@ static unsigned nv3TablePRAMIN_8BPP[][2] = {0x00000D10, 0x10118203}, {0x00000D14, 0x10110203}, {0x00000D18, 0x10110203}, - {0x00000D1C, 0x10419208} + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118203} }; static unsigned nv3TablePRAMIN_15BPP[][2] = { @@ -234,7 +243,8 @@ static unsigned nv3TablePRAMIN_15BPP[][2] = {0x00000D10, 0x10118200}, {0x00000D14, 0x10110200}, {0x00000D18, 0x10110200}, - {0x00000D1C, 0x10419208} + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118200} }; static unsigned nv3TablePRAMIN_32BPP[][2] = { @@ -246,7 +256,8 @@ static unsigned nv3TablePRAMIN_32BPP[][2] = {0x00000D10, 0x10118201}, {0x00000D14, 0x10110201}, {0x00000D18, 0x10110201}, - {0x00000D1C, 0x10419208} + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118201} }; static unsigned nv4TableFIFO[][2] = { @@ -370,6 +381,8 @@ static unsigned nv4TablePRAMIN[][2] = {0x00000009, 0x80011149}, {0x0000000A, 0x80000015}, {0x0000000B, 0x8001114A}, + {0x0000000C, 0x80000016}, + {0x0000000D, 0x8001114F}, {0x00000020, 0x80000000}, {0x00000021, 0x80011142}, {0x00000022, 0x80000001}, @@ -437,7 +450,10 @@ static unsigned nv4TablePRAMIN[][2] = {0x00000537, 0x00000000}, {0x00000538, 0x0000005B}, {0x0000053A, 0x11401140}, - {0x0000053B, 0x00000000} + {0x0000053B, 0x00000000}, + {0x0000053C, 0x0300A01C}, + {0x0000053E, 0x11401140}, + {0x0000053F, 0x00000000} }; static unsigned nv4TablePRAMIN_8BPP[][2] = { @@ -452,7 +468,8 @@ static unsigned nv4TablePRAMIN_8BPP[][2] = {0x0000052D, 0x00000302}, {0x0000052E, 0x00000302}, {0x00000535, 0x00000000}, - {0x00000539, 0x00000000} + {0x00000539, 0x00000000}, + {0x0000053D, 0x00000302} }; static unsigned nv4TablePRAMIN_15BPP[][2] = { @@ -467,7 +484,8 @@ static unsigned nv4TablePRAMIN_15BPP[][2] = {0x0000052D, 0x00000902}, {0x0000052E, 0x00000902}, {0x00000535, 0x00000702}, - {0x00000539, 0x00000702} + {0x00000539, 0x00000702}, + {0x0000053D, 0x00000902} }; static unsigned nv4TablePRAMIN_16BPP[][2] = { @@ -482,7 +500,8 @@ static unsigned nv4TablePRAMIN_16BPP[][2] = {0x0000052D, 0x00000C02}, {0x0000052E, 0x00000C02}, {0x00000535, 0x00000702}, - {0x00000539, 0x00000702} + {0x00000539, 0x00000702}, + {0x0000053D, 0x00000C02} }; static unsigned nv4TablePRAMIN_32BPP[][2] = { @@ -497,7 +516,8 @@ static unsigned nv4TablePRAMIN_32BPP[][2] = {0x0000052D, 0x00000E02}, {0x0000052E, 0x00000E02}, {0x00000535, 0x00000E02}, - {0x00000539, 0x00000E02} + {0x00000539, 0x00000E02}, + {0x0000053D, 0x00000E02} }; static unsigned nv10TableFIFO[][2] = { @@ -810,6 +830,8 @@ static unsigned nv10TablePRAMIN[][2] = {0x00000009, 0x80011149}, {0x0000000A, 0x80000015}, {0x0000000B, 0x8001114A}, + {0x0000000C, 0x80000016}, + {0x0000000D, 0x80011150}, {0x00000020, 0x80000000}, {0x00000021, 0x80011142}, {0x00000022, 0x80000001}, @@ -830,29 +852,45 @@ static unsigned nv10TablePRAMIN[][2] = {0x00000501, 0x01FFFFFF}, {0x00000502, 0x00000002}, {0x00000503, 0x00000002}, +#ifdef __BIG_ENDIAN + {0x00000508, 0x01088043}, +#else {0x00000508, 0x01008043}, +#endif {0x0000050A, 0x00000000}, {0x0000050B, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x0000050C, 0x01088019}, +#else {0x0000050C, 0x01008019}, +#endif {0x0000050E, 0x00000000}, {0x0000050F, 0x00000000}, -#if 1 - {0x00000510, 0x01008018}, +#ifdef __BIG_ENDIAN + {0x00000510, 0x01088018}, #else - {0x00000510, 0x01008044}, + {0x00000510, 0x01008018}, #endif {0x00000512, 0x00000000}, {0x00000513, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x00000514, 0x01088021}, +#else {0x00000514, 0x01008021}, +#endif {0x00000516, 0x00000000}, {0x00000517, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x00000518, 0x0108805F}, +#else {0x00000518, 0x0100805F}, +#endif {0x0000051A, 0x00000000}, {0x0000051B, 0x00000000}, -#if 1 - {0x0000051C, 0x0100804B}, +#ifdef __BIG_ENDIAN + {0x0000051C, 0x0108804B}, #else - {0x0000051C, 0x0100804A}, + {0x0000051C, 0x0100804B}, #endif {0x0000051E, 0x00000000}, {0x0000051F, 0x00000000}, @@ -868,10 +906,18 @@ static unsigned nv10TablePRAMIN[][2] = {0x00000529, 0x00000D01}, {0x0000052A, 0x11401140}, {0x0000052B, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x0000052C, 0x00080058}, +#else {0x0000052C, 0x00000058}, +#endif {0x0000052E, 0x11401140}, {0x0000052F, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x00000530, 0x00080059}, +#else {0x00000530, 0x00000059}, +#endif {0x00000532, 0x11401140}, {0x00000533, 0x00000000}, {0x00000534, 0x0000005A}, @@ -882,7 +928,14 @@ static unsigned nv10TablePRAMIN[][2] = {0x0000053B, 0x00000000}, {0x0000053C, 0x00000093}, {0x0000053E, 0x11401140}, - {0x0000053F, 0x00000000} + {0x0000053F, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x00000540, 0x0308A01C}, +#else + {0x00000540, 0x0300A01C}, +#endif + {0x00000542, 0x11401140}, + {0x00000543, 0x00000000} }; static unsigned nv10TablePRAMIN_8BPP[][2] = { @@ -898,7 +951,8 @@ static unsigned nv10TablePRAMIN_8BPP[][2] = {0x0000052E, 0x00000302}, {0x00000535, 0x00000000}, {0x00000539, 0x00000000}, - {0x0000053D, 0x00000000} + {0x0000053D, 0x00000000}, + {0x00000541, 0x00000302} }; static unsigned nv10TablePRAMIN_15BPP[][2] = { @@ -914,7 +968,8 @@ static unsigned nv10TablePRAMIN_15BPP[][2] = {0x0000052E, 0x00000902}, {0x00000535, 0x00000902}, {0x00000539, 0x00000902}, - {0x0000053D, 0x00000902} + {0x0000053D, 0x00000902}, + {0x00000541, 0x00000902} }; static unsigned nv10TablePRAMIN_16BPP[][2] = { @@ -930,7 +985,8 @@ static unsigned nv10TablePRAMIN_16BPP[][2] = {0x0000052E, 0x00000C02}, {0x00000535, 0x00000C02}, {0x00000539, 0x00000C02}, - {0x0000053D, 0x00000C02} + {0x0000053D, 0x00000C02}, + {0x00000541, 0x00000C02} }; static unsigned nv10TablePRAMIN_32BPP[][2] = { @@ -946,6 +1002,7 @@ static unsigned nv10TablePRAMIN_32BPP[][2] = {0x0000052E, 0x00000E02}, {0x00000535, 0x00000E02}, {0x00000539, 0x00000E02}, - {0x0000053D, 0x00000E02} + {0x0000053D, 0x00000E02}, + {0x00000541, 0x00000E02} }; diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h index f0bdd484ff37..9de0230fa8af 100644 --- a/drivers/video/riva/rivafb.h +++ b/drivers/video/riva/rivafb.h @@ -41,9 +41,16 @@ struct riva_par { u32 riva_palette[16]; u32 cursor_data[32 * 32/4]; int cursor_reset; + unsigned char *EDID; + unsigned int Chipset; + int forceCRTC; + Bool SecondCRTC; + int FlatPanel; #ifdef CONFIG_MTRR struct { int vram; int vram_valid; } mtrr; #endif }; +void riva_common_setup(struct riva_par *); + #endif /* __RIVAFB_H */ diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index fd6aba8342d7..bb95b6dc51ab 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -129,6 +129,40 @@ int xxxfb_init(void); int xxxfb_setup(char*); /** + * xxxfb_open - Optional function. Called when the framebuffer is + * first accessed. + * @info: frame buffer structure that represents a single frame buffer + * @user: tell us if the userland (value=1) or the console is accessing + * the framebuffer. + * + * This function is the first function called in the framebuffer api. + * Usually you don't need to provide this function. The case where it + * is used is to change from a text mode hardware state to a graphics + * mode state. + */ +static int xxxfb_open(const struct fb_info *info, int user) +{ + return 0; +} + +/** + * xxxfb_release - Optional function. Called when the framebuffer + * device is closed. + * @info: frame buffer structure that represents a single frame buffer + * @user: tell us if the userland (value=1) or the console is accessing + * the framebuffer. + * + * Thus function is called when we close /dev/fb or the framebuffer + * console system is released. Usually you don't need this function. + * The case where it is usually used is to go from a graphics state + * to a text mode state. + */ +static int xxxfb_release(const struct fb_info *info, int user) +{ + return 0; +} + +/** * xxxfb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer @@ -143,7 +177,10 @@ int xxxfb_setup(char*); * off by what the hardware can support then we alter the var PASSED in * to what we can do. If the hardware doesn't support mode change * a -EINVAL will be returned by the upper layers. You don't need to - * implement this function then. + * implement this function then. If you hardware doesn't support + * changing the resolution then this function is not needed. In this + * case the driver woudl just provide a var that represents the static + * state the screen is in. * * Returns negative errno on error, or zero on success. */ @@ -164,6 +201,7 @@ static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) * fb_info since we are using that data. This means we depend on the * data in var inside fb_info to be supported by the hardware. * xxxfb_check_var is always called before xxxfb_set_par to ensure this. + * Again if you can't can't the resolution you don't need this function. * */ static int xxxfb_set_par(struct fb_info *info) @@ -175,8 +213,8 @@ static int xxxfb_set_par(struct fb_info *info) /** * xxxfb_setcolreg - Optional function. Sets a color register. - * @regno: boolean, 0 copy local, 1 get_user() function - * @red: frame buffer colormap structure + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. @@ -284,12 +322,6 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, } /** - * xxxfb_cursor - - * - * Returns negative errno on error, or zero on success. - */ - -/** * xxxfb_pan_display - NOT a required function. Pans the display. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer @@ -299,7 +331,6 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, * If the values don't fit, return -EINVAL. * * Returns negative errno on error, or zero on success. - * */ static int xxxfb_pan_display(struct fb_var_screeninfo *var, const struct fb_info *info) @@ -335,12 +366,9 @@ static int xxxfb_blank(int blank_mode, const struct fb_info *info) /* * We provide our own functions if we have hardware acceleration * or non packed pixel format layouts. If we have no hardware - * acceleration, we use a generic unaccelerated function. If using - * a pack pixel format just use the functions in cfb*.c. Each file - * has one of the three different accel functions we support. You - * can use these functions as fallbacks if hardware unsupported - * action is requested. Also if you have non pack pixel modes and - * non accelerated cards you have to provide your own functions. + * acceleration, we can use a generic unaccelerated function. If using + * a pack pixel format just use the functions in cfb_*.c. Each file + * has one of the three different accel functions we support. */ /** @@ -349,41 +377,52 @@ static int xxxfb_blank(int blank_mode, const struct fb_info *info) * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer - * @x1: The x and y corrdinates of the upper left hand corner of the - * @y1: area we want to draw to. - * @width: How wide the rectangle is we want to draw. - * @height: How tall the rectangle is we want to draw. - * @color: The color to fill in the rectangle with. - * @rop: The rater operation. We can draw the rectangle with a COPY - * of XOR which provides erasing effect. + * @region: The structure representing the rectangular region we + * wish to draw to. * * This drawing operation places/removes a retangle on the screen * depending on the rastering operation with the value of color which * is in the current color depth format. */ -void xxxfb_fillrect(struct fb_info *p, struct fb_fillrect *region) +void xxfb_fillrect(struct fb_info *p, struct fb_fillrect *region) { +/* Meaning of struct fb_fillrect + * + * @dx: The x and y corrdinates of the upper left hand corner of the + * @dy: area we want to draw to. + * @width: How wide the rectangle is we want to draw. + * @height: How tall the rectangle is we want to draw. + * @color: The color to fill in the rectangle with. + * @rop: The raster operation. We can draw the rectangle with a COPY + * of XOR which provides erasing effect. + */ } /** * xxxfb_copyarea - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. - * Copies on area of the screen to another area. + * Copies one area of the screen to another area. * * @info: frame buffer structure that represents a single frame buffer - * @sx: The x and y corrdinates of the upper left hand corner of the - * @sy: source area on the screen. - * @width: How wide the rectangle is we want to copy. - * @height: How tall the rectangle is we want to copy. - * @dx: The x and y coordinates of the destination area on the screen. + * @area: Structure providing the data to copy the framebuffer contents + * from one region to another. * * This drawing operation copies a rectangular area from one area of the * screen to another area. */ void xxxfb_copyarea(struct fb_info *p, struct fb_copyarea *area) { +/* + * @dx: The x and y coordinates of the upper left hand corner of the + * @dy: destination area on the screen. + * @width: How wide the rectangle is we want to copy. + * @height: How tall the rectangle is we want to copy. + * @sx: The x and y coordinates of the upper left hand corner of the + * @sy: source area on the screen. + */ } + /** * xxxfb_imageblit - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. @@ -398,9 +437,89 @@ void xxxfb_copyarea(struct fb_info *p, struct fb_copyarea *area) */ void xxxfb_imageblit(struct fb_info *p, struct fb_image *image) { +/* + * @dx: The x and y coordinates of the upper left hand corner of the + * @dy: destination area to place the image on the screen. + * @width: How wide the image is we want to copy. + * @height: How tall the image is we want to copy. + * @fg_color: For mono bitmap images this is color data for + * @bg_color: the foreground and background of the image to + * write directly to the frmaebuffer. + * @depth: How many bits represent a single pixel for this image. + * @data: The actual data used to construct the image on the display. + * @cmap: The colormap used for color images. + */ } -/* ------------ Hardware Independent Functions ------------ */ +/** + * xxxfb_cursor - REQUIRED function. If your hardware lacks support + * for a cursor you can use the default cursor whose + * function is called soft_cursor. It will always + * work since it uses xxxfb_imageblit function which + * is required. + * + * @info: frame buffer structure that represents a single frame buffer + * @cursor: structure defining the cursor to draw. + * + * This operation is used to set or alter the properities of the + * cursor. + * + * Returns negative errno on error, or zero on success. + */ +int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ +/* + * @set: Which fields we are altering in struct fb_cursor + * @enable: Disable or enable the cursor + * @rop: The bit operation we want to do. + * @mask: This is the cursor mask bitmap. + * @dest: A image of the area we are going to display the cursor. + * Used internally by the driver. + * @hot: The hot spot. + * @image: The actual data for the cursor image. + */ +} + +/** + * xxxfb_rotate - NOT a required function. If your hardware + * supports rotation the whole screen then + * you would provide a hook for this. + * + * @info: frame buffer structure that represents a single frame buffer + * @angle: The angle we rotate the screen. + * + * This operation is used to set or alter the properities of the + * cursor. + */ +void xxxfb_rotate(struct fb_info *info, int angle) +{ +} + +/** + * xxxfb_poll - NOT a required function. The purpose of this + * function is to provide a way for some process + * to wait until a specific hardware event occurs + * for the framebuffer device. + * + * @info: frame buffer structure that represents a single frame buffer + * @wait: poll table where we store process that await a event. + */ +void xxxfb_poll(struct fb_info *info, poll_table *wait) +{ +} + +/** + * xxxfb_sync - NOT a required function. Normally the accel engine + * for a graphics card take a specific amount of time. + * Often we have to wait for the accelerator to finish + * its operation before we can write to the framebuffer + * so we can have consistant display output. + * + * @info: frame buffer structure that represents a single frame buffer + */ +void xxxfb_sync(struct fb_info *info) +{ +} /* * Initialization @@ -480,39 +599,32 @@ int __init xxxfb_setup(char *options) /* Parse user speficied options (`video=xxxfb:') */ } - /* ------------------------------------------------------------------------- */ /* * Frame buffer operations */ -/* If all you need is that - just don't define ->fb_open */ -static int xxxfb_open(const struct fb_info *info, int user) -{ - return 0; -} - -/* If all you need is that - just don't define ->fb_release */ -static int xxxfb_release(const struct fb_info *info, int user) -{ - return 0; -} - static struct fb_ops xxxfb_ops = { .owner = THIS_MODULE, - .fb_open = xxxfb_open, /* only if you need it to do something */ - .fb_release = xxxfb_release, /* only if you need it to do something */ + .fb_open = xxxfb_open, + .fb_read = xxxfb_read, + .fb_write = xxxfb_write, + .fb_release = xxxfb_release, .fb_check_var = xxxfb_check_var, - .fb_set_par = xxxfb_set_par, /* optional */ + .fb_set_par = xxxfb_set_par, .fb_setcolreg = xxxfb_setcolreg, - .fb_blank = xxxfb_blank, /* optional */ - .fb_pan_display = xxxfb_pan_display, /* optional */ - .fb_fillrect = xxxfb_fillrect, - .fb_copyarea = xxxfb_copyarea, - .fb_imageblit = xxxfb_imageblit, - .fb_ioctl = xxxfb_ioctl, /* optional */ - .fb_mmap = xxxfb_mmap, /* optional */ + .fb_blank = xxxfb_blank, + .fb_pan_display = xxxfb_pan_display, + .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ + .fb_copyarea = xxxfb_copyarea, /* Needed !!! */ + .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ + .fb_cursor = xxxfb_cursor, /* Needed !!! */ + .fb_rotate = xxxfb_rotate, + .fb_poll = xxxfb_poll, + .fb_sync = xxxfb_sync, + .fb_ioctl = xxxfb_ioctl, + .fb_mmap = xxxfb_mmap, }; /* ------------------------------------------------------------------------- */ diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 024a4fb2e963..d8e483bde68a 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -7,13 +7,15 @@ * * Contributions (and many thanks) : * - * 03/2001 James Simmons <jsimmons@linux-fbdev.org> + * 03/2001 James Simmons <jsimmons@infradead.org> * 04/2001 Paul Mundt <lethal@chaoticdreams.org> * 05/2001 Urs Ganse <ursg@uni.de> - * (initial work on voodoo2 port, interlace) + * (initial work on voodoo2 port, interlace) + * 09/2002 Helge Deller <deller@gmx.de> + * (enable driver on big-endian machines (hppa), ioctl fixes) + * 12/2002 Helge Deller <deller@gmx.de> + * (port driver to new frambuffer infrastructure) * - * - * $Id: sstfb.c,v 1.37 2002/05/10 19:35:11 ghoz Exp $ */ /* @@ -27,13 +29,9 @@ * misc notes, TODOs, toASKs, and deep thoughts -TODO: at one time or another test that the mode is acceptable by the monitor --ASK: I can choose different ordering for the color bitfields (rgba argb ...) +-ASK: Can I choose different ordering for the color bitfields (rgba argb ...) wich one should i use ? is there any preferred one ? It seems ARGB is the one ... --ASK: later: how to cope with endianness ? the fbi chip has builtin functions - to do byte swizling /swapping, maybe use that ... --TODO: check the error paths . if something get wrong, the error doesn't seem - to be very well handled...if handled at all.. not good. -TODO: in set_var check the validity of timings (hsync vsync)... -TODO: check and recheck the use of sst_wait_idle : we dont flush the fifo via a nop command . so it's ok as long as the commands we pass don't go @@ -42,9 +40,7 @@ state. -FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20) -ASK: I stole "inverse" but seems it doesn't work... check what it realy does... --TODO: change struct sst_info fb_info from static to array/dynamic - - * +-TODO: change struct fb_info fb_info from static to array/dynamic */ /* @@ -62,24 +58,20 @@ * SST_DEBUG_VAR : debug display/var structs * 0 : no debug * 1 : dumps display, fb_var - * SST_DEBUG_IOCTL : enable sstfb specific ioctls - * 0 : disable - * 1 : enable debug ioctls : + * + * sstfb specific ioctls: * toggle vga (0x46db) : toggle vga_pass_through * fill fb (0x46dc) : fills fb - * dump var (0x46dd) : logs display[0-5].var - * test disp (0x46de) : draws a test motif + * test disp (0x46de) : draws a test image */ -#define SST_DEBUG -//#undef SST_DEBUG +#undef SST_DEBUG #define SST_DEBUG_REG 0 #define SST_DEBUG_FUNC 0 #define SST_DEBUG_VAR 0 -#define SST_DEBUG_IOCTL 1 -/* #define EN_24_32_BPP *//* enable 24/32 bpp functions for testing only */ +/* enable 24/32 bpp functions ? (completely untested!) */ #undef EN_24_32_BPP /* @@ -88,16 +80,16 @@ 1 640x480@75 took from glide 2 1024x768@76 std fb.mode 3 640x480@60 glide default */ -#define DEFAULT_MODE 1 +#define DEFAULT_MODE 3 + /* * Includes */ -#include <linux/string.h> #include <linux/config.h> +#include <linux/string.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/tty.h> #include <linux/fb.h> #include <linux/pci.h> #include <linux/delay.h> @@ -107,145 +99,33 @@ #include <asm/io.h> #include <asm/ioctl.h> - -#include <video/fbcon.h> -#include <video/fbcon-cfb16.h> -#ifdef EN_24_32_BPP -# include <video/fbcon-cfb24.h> -# include <video/fbcon-cfb32.h> -#endif +#include <asm/uaccess.h> #include "sstfb.h" -void __Dump_regs(struct sstfb_info *); -#define Dump_regs __Dump_regs(sst_info) //XXX - -/********/ /* initialized by setup */ -static int inverse; /* =0 */ /* invert colormap */ -static int vgapass; /* =0 */ /* enable Vga passthrough cable */ -static int mem; /* =0 */ /* mem size in Mb , 0 = autodetect */ + +static int inverse; /* invert colormap */ +static int vgapass; /* enable Vga passthrough cable */ +static int mem; /* mem size in Mb , 0 = autodetect */ static int clipping = 1; /* use clipping (slower, safer) */ -static int gfxclk; /* =0 */ /* force FBI freq in Mhz . Dangerous */ -static int slowpci; /* =0 */ /* slow PCI settings */ +static int gfxclk; /* force FBI freq in Mhz . Dangerous */ +static int slowpci; /* slow PCI settings */ static int dev = -2; /* specify device (0..n) -2=all -1=none*/ -static char * mode_option ; - - -/********/ - -int sstfb_init(void); -int sstfb_setup(char *options); -static int __devinit sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id); -static void __devexit sstfb_remove(struct pci_dev *pdev); - - -/* Framebuffer API */ -static int sstfb_open(struct fb_info *info, int user); -static int sstfb_release(struct fb_info *info, int user); -static int sstfb_get_fix(struct fb_fix_screeninfo *fix, - int con, struct fb_info *info); -static int sstfb_get_var(struct fb_var_screeninfo *var, - int con, struct fb_info *info); -static int sstfb_set_var(struct fb_var_screeninfo *var, - int con, struct fb_info *info); -static int sstfb_get_cmap(struct fb_cmap *cmap, int kspc, - int con, struct fb_info *info); -static int sstfb_set_cmap(struct fb_cmap *cmap, int kspc, - int con, struct fb_info *info); -static int sstfb_pan_display(struct fb_var_screeninfo *var, - int con, struct fb_info *info); -static int sstfb_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg, int con, - struct fb_info *info); - -/* Interface to the low level console driver */ -static int sstfbcon_switch(int con, struct fb_info *info); -static int sstfbcon_updatevar(int con, struct fb_info *info); -static void sstfbcon_blank(int blank, struct fb_info *info); - -/* Internal routines */ -static void sstfb_install_cmap(int con, struct fb_info *info); -static int sstfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); -static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); - -static int sstfb_set_par(const struct sstfb_par *par, - struct sstfb_info *sst_info); -static int sstfb_decode_var (const struct fb_var_screeninfo *var, - struct sstfb_par *par, - const struct sstfb_info *sst_info); -static int sstfb_encode_var (struct fb_var_screeninfo *var, - const struct sstfb_par *par, - const struct sstfb_info *sst_info); - -static void sstfb_test16(struct sstfb_info *sst_info); - -#ifdef EN_24_32_BPP -static void sstfb_test32(struct sstfb_info *sst_info); -#endif - -/* Low level routines */ -static int sst_get_memsize(struct sstfb_info *sst_info, u_long *memsize); -static int __sst_wait_idle(u_long vbase); -#define sst_wait_idle() __sst_wait_idle(sst_info->mmio.vbase) -static int sst_detect_dactype(struct sstfb_info *sst_info); -static int sst_detect_att(struct sstfb_info *sst_info); -static int sst_detect_ti(struct sstfb_info *sst_info); -static int sst_detect_ics(struct sstfb_info *sst_info); -static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t); -static int sst_set_pll_att_ti(struct sstfb_info *sst_info, const struct pll_timing *t, const int clock); -static int sst_set_pll_ics(struct sstfb_info *sst_info, const struct pll_timing *t, const int clock); -static void sst_set_vidmod_att_ti(struct sstfb_info *sst_info, const int bpp); -static void sst_set_vidmod_ics(struct sstfb_info *sst_info, const int bpp); -static int sst_init(struct sstfb_info *sst_info); -static void sst_shutdown(struct sstfb_info *sst_info); - -static struct fb_ops sstfb_ops = { - .owner = THIS_MODULE, - .fb_open = sstfb_open, - .fb_release = sstfb_release, - .fb_get_fix = sstfb_get_fix, - .fb_get_var = sstfb_get_var, - .fb_set_var = sstfb_set_var, - .fb_get_cmap = sstfb_get_cmap, - .fb_set_cmap = sstfb_set_cmap, - .fb_pan_display = sstfb_pan_display, - .fb_ioctl = sstfb_ioctl, -}; +static char *mode_option __devinitdata; enum { ID_VOODOO1 = 0, ID_VOODOO2 = 1, }; -#define IS_VOODOO2(info) ((info)->type == ID_VOODOO2 ) +#define IS_VOODOO2(par) ((par)->type == ID_VOODOO2 ) static struct sst_spec voodoo_spec[] __devinitdata = { - { .name = "Voodoo Graphics", - .default_gfx_clock = 50000, - .max_gfxclk = 60, }, - { .name = "Voodoo2", - .default_gfx_clock = 75000, - .max_gfxclk = 85, }, -}; - -static struct pci_device_id sstfb_id_tbl[] __devinitdata = { - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 }, - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 }, - { 0 }, -}; - -static struct pci_driver sstfb_driver = { - .name = "sstfb", - .id_table = sstfb_id_tbl, - .probe = sstfb_probe, - .remove = __devexit_p(sstfb_remove), + { .name = "Voodoo Graphics", .default_gfx_clock = 50000, .max_gfxclk = 60 }, + { .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 }, }; static struct fb_var_screeninfo sstfb_default = @@ -256,55 +136,88 @@ static struct fb_var_screeninfo sstfb_default = 0, 0, -1, -1, 0, 25000, 86, 41, 23, 1, 127, 4, 0, FB_VMODE_NONINTERLACED }; -#endif -#if ( DEFAULT_MODE == 1 ) +#elif ( DEFAULT_MODE == 1 ) {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */ 640, 480, 640, 480, 0, 0, 16, 0, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 31746, 118, 17, 16, 1, 63, 3, 0, FB_VMODE_NONINTERLACED }; -#endif -#if ( DEFAULT_MODE == 2 ) +#elif ( DEFAULT_MODE == 2 ) { /* 1024x768@76 took from my /etc/fb.modes */ 1024, 768, 1024, 768,0, 0, 16,0, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 11764, 208, 8, 36, 16, 120, 3 , 0, FB_VMODE_NONINTERLACED }; -#endif -#if ( DEFAULT_MODE == 3 ) +#elif ( DEFAULT_MODE == 3 ) { /* 640x480@60 , 16bpp glide default ?*/ 640, 480, 640, 480, 0, 0, 16, 0, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 39721 , 38, 26 , 25 ,18 , 96 ,2, 0, FB_VMODE_NONINTERLACED }; +#elif + #error "Invalid DEFAULT_MODE value !" #endif -static struct dac_switch dacs[] __devinitdata = { - { .name = "TI TVP3409", - .detect = sst_detect_ti, - .set_pll = sst_set_pll_att_ti, - .set_vidmod = sst_set_vidmod_att_ti }, - - { .name = "AT&T ATT20C409", - .detect = sst_detect_att, - .set_pll = sst_set_pll_att_ti, - .set_vidmod = sst_set_vidmod_att_ti }, - { .name = "ICS ICS5342", - .detect = sst_detect_ics, - .set_pll = sst_set_pll_ics, - .set_vidmod = sst_set_vidmod_ics }, -}; - /* - * - * Definitions - * + * debug functions */ +static void sstfb_test16(struct fb_info *info); +#if EN_24_32_BPP +static void sstfb_test32(struct fb_info *info); +#endif + +#if 0 +static void __Dump_regs (struct sstfb_info *sst_info) +{ + struct { u32 reg ; char * reg_name;} pci_regs [] = { + { PCI_INIT_ENABLE, "initenable"}, + { PCI_VCLK_ENABLE, "enable vclk"}, + { PCI_VCLK_DISABLE, "disable vclk"}, + }; + + struct { u32 reg ; char * reg_name;} sst_regs [] = { + {FBIINIT0,"fbiinit0"}, + {FBIINIT1,"fbiinit1"}, + {FBIINIT2,"fbiinit2"}, + {FBIINIT3,"fbiinit3"}, + {FBIINIT4,"fbiinit4"}, + {FBIINIT5,"fbiinit5"}, + {FBIINIT6,"fbiinit6"}, + {FBIINIT7,"fbiinit7"}, + {LFBMODE,"lfbmode"}, + {FBZMODE,"fbzmode"}, + }; + int pci_s = sizeof(pci_regs)/sizeof(*pci_regs); + int sst_s = sizeof(sst_regs)/sizeof(*sst_regs); + u32 pci_res[pci_s]; + u32 sst_res[sst_s]; + + struct pci_dev * dev = sst_info->dev; + + int i; + + for (i=0; i < pci_s ; i++ ) { + pci_read_config_dword ( dev, pci_regs[i].reg , &pci_res[i]) ; + } + for (i=0; i < sst_s ; i++ ) { + sst_res[i]=sst_read(sst_regs[i].reg); + } + + dprintk ("Dump regs\n"); + for (i=0; i < pci_s ; i++ ) { + dprintk("%s = %0#10x\n", pci_regs[i].reg_name , pci_res[i]) ; + } + for (i=0; i < sst_s ; i++ ) { + dprintk("%s = %0#10x\n", sst_regs[i].reg_name , sst_res[i]) ; + } +} +#endif + #if (SST_DEBUG_VAR > 0) /* debug info / dump a fb_var_screeninfo */ static void sst_dbg_print_var(struct fb_var_screeninfo *var) { @@ -331,15 +244,16 @@ static void sst_dbg_print_var(struct fb_var_screeninfo *var) { #if (SST_DEBUG_REG > 0) static void sst_dbg_print_read_reg (u32 reg, u32 val) { - char * regname =NULL; + const char *regname; switch (reg) { - case FBIINIT0: regname="FbiInit0"; break; - case FBIINIT1: regname="FbiInit1"; break; - case FBIINIT2: regname="FbiInit2"; break; - case FBIINIT3: regname="FbiInit3"; break; - case FBIINIT4: regname="FbiInit4"; break; - case FBIINIT5: regname="FbiInit5"; break; - case FBIINIT6: regname="FbiInit6"; break; + case FBIINIT0: regname = "FbiInit0"; break; + case FBIINIT1: regname = "FbiInit1"; break; + case FBIINIT2: regname = "FbiInit2"; break; + case FBIINIT3: regname = "FbiInit3"; break; + case FBIINIT4: regname = "FbiInit4"; break; + case FBIINIT5: regname = "FbiInit5"; break; + case FBIINIT6: regname = "FbiInit6"; break; + default: regname = NULL; break; } if (regname == NULL) r_ddprintk("sst_read(%#x): %#x\n", reg, val); @@ -348,16 +262,16 @@ static void sst_dbg_print_read_reg (u32 reg, u32 val) { } static void sst_dbg_print_write_reg (u32 reg, u32 val) { - char * regname = NULL; - + const char *regname; switch (reg) { - case FBIINIT0: regname="FbiInit0"; break; - case FBIINIT1: regname="FbiInit1"; break; - case FBIINIT2: regname="FbiInit2"; break; - case FBIINIT3: regname="FbiInit3"; break; - case FBIINIT4: regname="FbiInit4"; break; - case FBIINIT5: regname="FbiInit5"; break; - case FBIINIT6: regname="FbiInit6"; break; + case FBIINIT0: regname = "FbiInit0"; break; + case FBIINIT1: regname = "FbiInit1"; break; + case FBIINIT2: regname = "FbiInit2"; break; + case FBIINIT3: regname = "FbiInit3"; break; + case FBIINIT4: regname = "FbiInit4"; break; + case FBIINIT5: regname = "FbiInit5"; break; + case FBIINIT6: regname = "FbiInit6"; break; + default: regname = NULL; break; } if (regname == NULL) r_ddprintk("sst_write(%#x, %#x)\n", reg, val); @@ -365,25 +279,27 @@ static void sst_dbg_print_write_reg (u32 reg, u32 val) { r_dprintk(" sst_write(%s, %#x)\n", regname, val); } #else /* (SST_DEBUG_REG > 0) */ -# define sst_dbg_print_read_reg(reg, val) do {}while(0) -# define sst_dbg_print_write_reg(reg, val) do {}while(0) +# define sst_dbg_print_read_reg(reg, val) do {} while(0) +# define sst_dbg_print_write_reg(reg, val) do {} while(0) #endif /* (SST_DEBUG_REG > 0) */ +/* + * hardware access functions + */ + /* register access */ -#define sst_read(reg) __sst_read(sst_info->mmio.vbase, reg) -#define sst_write(reg,val) __sst_write(sst_info->mmio.vbase, reg, val) -#define sst_set_bits(reg,val) __sst_set_bits(sst_info->mmio.vbase, reg, val) -#define sst_unset_bits(reg,val) __sst_unset_bits(sst_info->mmio.vbase, reg, val) -#define sst_dac_read(reg) __sst_dac_read(sst_info->mmio.vbase, reg) -#define sst_dac_write(reg,val) __sst_dac_write(sst_info->mmio.vbase, reg, val) -#define dac_i_read(reg) __dac_i_read(sst_info->mmio.vbase, reg) -#define dac_i_write(reg,val) __dac_i_write(sst_info->mmio.vbase, reg, val) +#define sst_read(reg) __sst_read(par->mmio_vbase, reg) +#define sst_write(reg,val) __sst_write(par->mmio_vbase, reg, val) +#define sst_set_bits(reg,val) __sst_set_bits(par->mmio_vbase, reg, val) +#define sst_unset_bits(reg,val) __sst_unset_bits(par->mmio_vbase, reg, val) +#define sst_dac_read(reg) __sst_dac_read(par->mmio_vbase, reg) +#define sst_dac_write(reg,val) __sst_dac_write(par->mmio_vbase, reg, val) +#define dac_i_read(reg) __dac_i_read(par->mmio_vbase, reg) +#define dac_i_write(reg,val) __dac_i_write(par->mmio_vbase, reg, val) static inline u32 __sst_read(u_long vbase, u32 reg) { - u32 ret; - - ret = readl(vbase + reg); + u32 ret = readl(vbase + reg); sst_dbg_print_read_reg(reg, ret); return ret; } @@ -406,6 +322,37 @@ static inline void __sst_unset_bits(u_long vbase, u32 reg, u32 val) __sst_write(vbase, reg, __sst_read(vbase, reg) & ~val); } +/* + * wait for the fbi chip. ASK: what happens if the fbi is stuck ? + * + * the FBI is supposed to be ready if we receive 5 time + * in a row a "idle" answer to our requests + */ + +#define sst_wait_idle() __sst_wait_idle(par->mmio_vbase) + +static int __sst_wait_idle(u_long vbase) +{ + int count = 0; + + f_ddprintk("sst_wait_idle\n"); + while(1) { + if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) { + f_dddprintk("status: busy\n"); +/* FIXME basicaly, this is a busy wait. maybe not that good. oh well; + * this is a small loop after all. + * Or maybe we should use mdelay() or udelay() here instead ? */ + count = 0; + } else { + count++; + f_dddprintk("status: idle(%d)\n", count); + } + if (count >= 5) return 1; +/* XXX do something to avoid hanging the machine if the voodoo is out */ + } +} + + /* dac access */ /* dac_read should be remaped to FbiInit2 (via the pci reg init_enable) */ static u8 __sst_dac_read(u_long vbase, u8 reg) @@ -421,10 +368,10 @@ static u8 __sst_dac_read(u_long vbase, u8 reg) reg &= 0x07; __sst_write(vbase, DAC_DATA, ((u32)reg << 8) | DAC_READ_CMD ); __sst_wait_idle(vbase); - /*udelay(10);*/ - ret=(__sst_read(vbase, DAC_READ) & 0xff); + /* udelay(10); */ + ret = __sst_read(vbase, DAC_READ) & 0xff; r_dprintk("sst_dac_read(%#x): %#x\n", reg, ret); - return (u8)ret; + return ret; } static void __sst_dac_write(u_long vbase, u8 reg, u8 val) @@ -456,270 +403,188 @@ static void __dac_i_write(u_long vbase, u8 reg,u8 val) __sst_dac_write(vbase, DACREG_DATA_I, val); } -/* - * - * Internal routines +/* compute the m,n,p , returns the real freq + * (ics datasheet : N <-> N1 , P <-> N2) * + * Fout= Fref * (M+2)/( 2^P * (N+2)) + * we try to get close to the asked freq + * with P as high, and M as low as possible + * range: + * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63 + * ics : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31 + * we'll use the lowest limitation, should be precise enouth */ - -static void sstfb_install_cmap(int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) - f_dprintk("sstfb_install_cmap(con: %d)\n",con); - f_ddprintk("currcon: %d\n", sst_info->currcon); - if (con != sst_info->currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sstfb_setcolreg, info); - else - fb_set_cmap( - fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, sstfb_setcolreg, info); -#undef sst_info -} - -static int sstfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) - f_dddprintk("sstfb_getcolreg\n"); - if (regno >= 16) return 1; - - *red = sst_info->palette[regno].red; - *green = sst_info->palette[regno].green; - *blue = sst_info->palette[regno].blue; - *transp = sst_info->palette[regno].transp; - f_dddprintk("%-2d rvba: %#x, %#x, %#x, %#x\n", - regno,*red, *green, *blue, *transp); - return 0; -#undef sst_info -} - -static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t) { -#define sst_info ((struct sstfb_info *) info) - u32 col; - struct display * disp; + int m, m2, n, p, best_err, fout; + int best_n = -1; + int best_m = -1; - f_dddprintk("sstfb_setcolreg\n"); - f_dddprintk("%-2d rvba: %#x, %#x, %#x, %#x\n", - regno, red, green, blue, transp); - if (regno >= 16) return 1; + f_dprintk("sst_calc_pll(%dKhz)\n", freq); + best_err = freq; + p = 3; + /* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/ + while (((1 << p) * freq > VCO_MAX) && (p >= 0)) + p--; + if (p == -1) + return -EINVAL; + for (n = 1; n < 32; n++) { + /* calc 2 * m so we can round it later*/ + m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ; - sst_info->palette[regno].red = red; - sst_info->palette[regno].green = green; - sst_info->palette[regno].blue = blue; - sst_info->palette[regno].transp= transp; - - disp=&sst_info->disp; - red >>= (16 - disp->var.red.length); - green >>= (16 - disp->var.green.length); - blue >>= (16 - disp->var.blue.length); - transp >>= (16 - disp->var.transp.length); - col = (red << disp->var.red.offset) - | (green << disp->var.green.offset) - | (blue << disp->var.blue.offset) - | (transp << disp->var.transp.offset); - - switch(disp->var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB16 - case 16: - sst_info->fbcon_cmap.cfb16[regno]=(u16)col; - break; -#endif -#ifdef EN_24_32_BPP -#ifdef FBCON_HAS_CFB24 - case 24: - sst_info->fbcon_cmap.cfb32[regno]=col; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - sst_info->fbcon_cmap.cfb32[regno]=col; - break; -#endif -#endif - default: - eprintk("bug line %d: bad depth '%u'\n",__LINE__, - disp->var.bits_per_pixel); - break; + m = (m2 % 2 ) ? m2/2+1 : m2/2 ; + if (m >= 128) + break; + fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2)); + if ((ABS(fout - freq) < best_err) && (m > 0)) { + best_n = n; + best_m = m; + best_err = ABS(fout - freq); + /* we get the lowest m , allowing 0.5% error in freq*/ + if (200*best_err < freq) break; + } } - f_dddprintk("bpp: %d . encoded color: %#x\n", - disp->var.bits_per_pixel, col); + if (best_n == -1) /* unlikely, but who knows ? */ + return -EINVAL; + t->p = p; + t->n = best_n; + t->m = best_m; + *freq_out = (DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2)); + f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n", + t->m, t->n, t->p, *freq_out); return 0; -#undef sst_info } -/* set par according to var ( checks var ) */ -static int sstfb_decode_var (const struct fb_var_screeninfo *var, - struct sstfb_par *par, - const struct sstfb_info *sst_info) +/* + * Frame buffer API + */ +static int sstfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { - int real_length; - - f_dprintk("sstfb_decode_var\n"); - /* Check var validity */ - par->valid=0; - - memset(par, 0, sizeof(par)); - par->xDim = var->xres; - par->hSyncOn = var->hsync_len; - par->hSyncOff = var->xres + var->right_margin + var->left_margin; - par->hBackPorch = var->left_margin; - par->yDim = var->yres; - par->vSyncOn = var->vsync_len; - par->vSyncOff = var->yres + var->lower_margin + var->upper_margin; - par->vBackPorch = var->upper_margin; - - if(sst_calc_pll (PS2KHZ(var->pixclock), &par->freq, &par->pll)) { - eprintk("Pixclock %d out of range\n", var->pixclock); - return -EINVAL; //XXX + struct sstfb_par *par = (struct sstfb_par *) info->par; + int hSyncOff = var->xres + var->right_margin + var->left_margin; + int vSyncOff = var->yres + var->lower_margin + var->upper_margin; + int vBackPorch = var->left_margin, yDim = var->yres, vSyncOn = var->vsync_len; + int tiles_in_X, real_length; + unsigned int freq; + + f_dprintk("sstfb_check_var()\n"); + + if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) { + eprintk("Pixclock at %ld KHZ out of range\n", PICOS2KHZ(var->pixclock)); + return -EINVAL; } - - par->sync=var->sync & (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); - - par->vmode=var->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE); - /* in laced mode, vBackPorch should be even. odd -> funky display */ - if (par->vmode & FB_VMODE_INTERLACED) - par->vBackPorch += (par->vBackPorch % 2); - if (par->vmode & FB_VMODE_DOUBLE) { - par->vBackPorch <<= 1; - par->yDim <<=1; - par->vSyncOn <<=1; - par->vSyncOff <<=1; + var->pixclock = KHZ2PICOS(freq); + + if (var->vmode & FB_VMODE_INTERLACED) + vBackPorch += (vBackPorch % 2); + if (var->vmode & FB_VMODE_DOUBLE) { + vBackPorch <<= 1; + yDim <<=1; + vSyncOn <<=1; + vSyncOff <<=1; } switch (var->bits_per_pixel) { case 0 ... 16 : - par->bpp = 16; + var->bits_per_pixel = 16; break; #ifdef EN_24_32_BPP case 17 ... 24 : - par->bpp = 24; + var->bits_per_pixel = 24; break; case 25 ... 32 : - par->bpp = 32; + var->bits_per_pixel = 32; break; #endif default : - eprintk ("Unsupported bpp %d\n", par->bpp); + eprintk("Unsupported bpp %d\n", var->bits_per_pixel); return -EINVAL; break; } - - if (IS_VOODOO2(sst_info)) { - /* voodoo2 has 32 pixel wide tiles , BUT stange things - happen with odd number of tiles */ - par->tiles_in_X= (par->xDim + 63 ) / 64 * 2; - } else { - /* voodoo1 has 64 pixels wide tiles. */ - par->tiles_in_X= (par->xDim + 63 ) / 64; - } - + /* validity tests */ - if((par->xDim <= 1) || (par->yDim <= 0 ) - || (par->hSyncOn <= 1) - || (par->hSyncOff <= 1) - || (par->hBackPorch <= 2) - || (par->vSyncOn <= 0) - || (par->vSyncOff <= 0) - || (par->vBackPorch <= 0) - || (par->tiles_in_X <= 0)) { + if ((var->xres <= 1) || (yDim <= 0 ) + || (var->hsync_len <= 1) + || (hSyncOff <= 1) + || (var->left_margin <= 2) + || (vSyncOn <= 0) + || (vSyncOff <= 0) + || (vBackPorch <= 0)) { return -EINVAL; } - if (IS_VOODOO2(sst_info)) { + + if (IS_VOODOO2(par)) { /* Voodoo 2 limits */ - if(((par->xDim-1) >= POW2(11)) || (par->yDim >= POW2(11))) { - eprintk ("Unsupported resolution %dx%d\n", + tiles_in_X = (var->xres + 63 ) / 64 * 2; + + if (((var->xres - 1) >= POW2(11)) || (yDim >= POW2(11))) { + eprintk("Unsupported resolution %dx%d\n", var->xres, var->yres); return -EINVAL; } - if (((par->hSyncOn-1) >= POW2(9)) - || ((par->hSyncOff-1) >= POW2(11)) - || ((par->hBackPorch-2) >= POW2(9)) - || (par->vSyncOn >= POW2(13)) - || (par->vSyncOff >= POW2(13)) - || (par->vBackPorch >= POW2(9)) - || (par->tiles_in_X >= POW2(6))) { - eprintk ("Unsupported Timing\n"); + + if (((var->hsync_len-1) >= POW2(9)) + || ((hSyncOff-1) >= POW2(11)) + || ((var->left_margin - 2) >= POW2(9)) + || (vSyncOn >= POW2(13)) + || (vSyncOff >= POW2(13)) + || (vBackPorch >= POW2(9)) + || (tiles_in_X >= POW2(6)) + || (tiles_in_X <= 0)) { + eprintk("Unsupported Timings\n"); return -EINVAL; } } else { /* Voodoo limits */ - if (par->vmode) { + tiles_in_X = (var->xres + 63 ) / 64; + + if (var->vmode) { eprintk("Interlace/Doublescan not supported %#x\n", - par->vmode); + var->vmode); return -EINVAL; } - if(((par->xDim-1) >= POW2(10)) || (par->yDim >= POW2(10))) { - eprintk ("Unsupported resolution %dx%d\n", + if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) { + eprintk("Unsupported resolution %dx%d\n", var->xres, var->yres); return -EINVAL; } - if (((par->hSyncOn-1) >= POW2(8)) - || ((par->hSyncOff-1) >= POW2(10)) - || ((par->hBackPorch-2) >= POW2(8)) - || (par->vSyncOn >= POW2(12)) - || (par->vSyncOff >= POW2(12)) - || (par->vBackPorch >= POW2(8)) - || (par->tiles_in_X >= POW2(4))) { - eprintk ("Unsupported Timings\n"); + if (((var->hsync_len - 1) >= POW2(8)) + || ((hSyncOff-1) >= POW2(10)) + || ((var->left_margin - 2) >= POW2(8)) + || (vSyncOn >= POW2(12)) + || (vSyncOff >= POW2(12)) + || (vBackPorch >= POW2(8)) + || (tiles_in_X >= POW2(4)) + || (tiles_in_X <= 0)) { + eprintk("Unsupported Timings\n"); return -EINVAL; } } - /* it seems that the fbi uses tiles of 64x16 pixels to "map" the mem*/ - /* FIXME: i don't like this... looks wrong*/ - real_length = par->tiles_in_X * (IS_VOODOO2(sst_info) ? 32 : 64 ) - * ((par->bpp == 16) ? 2 : 4); + /* it seems that the fbi uses tiles of 64x16 pixels to "map" the mem */ + /* FIXME: i don't like this... looks wrong */ + real_length = tiles_in_X * (IS_VOODOO2(par) ? 32 : 64 ) + * ((var->bits_per_pixel == 16) ? 2 : 4); - if ((real_length * var->yres) > sst_info->video.len) { - eprintk ("Not enough video memory\n"); + if ((real_length * yDim) > info->fix.smem_len) { + eprintk("Not enough video memory\n"); return -ENOMEM; } - par->valid=1; - return 0; -} -/* sets var according to par (basicaly, sets sane values) */ -static int sstfb_encode_var (struct fb_var_screeninfo *var, - const struct sstfb_par *par, - const struct sstfb_info *sst_info) -{ - memset(var,0,sizeof(struct fb_var_screeninfo)); - - var->xres = par->xDim; - var->yres = par->yDim; - var->xres_virtual = par->xDim; - var->yres_virtual = par->yDim; - var->bits_per_pixel = par->bpp; - /* {x|y}offset = 0 */ - var->height = -1; - var->width = -1; - var->pixclock = KHZ2PS(par->freq); - var->left_margin = par->hBackPorch; - var->right_margin = par->hSyncOff - par->xDim - par->hBackPorch; - var->upper_margin = par->vBackPorch; - var->lower_margin = par->vSyncOff - par->yDim - par->vBackPorch; - var->hsync_len = par->hSyncOn; - var->vsync_len = par->vSyncOn; - var->sync = par->sync; - var->vmode = par->vmode; - if (var->vmode & FB_VMODE_DOUBLE) { - var->yres >>=1; - var->yres_virtual >>=1; - var->vsync_len >>=1; - var->upper_margin >>=1; - var->lower_margin >>=1; - } + var->sync &= (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); + var->vmode &= (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE); + var->xoffset = 0; + var->yoffset = 0; + var->height = -1; + var->width = -1; /* * correct the color bit fields */ - /* var->{red|green|blue}.msb_right = 0; */ + /* var->{red|green|blue}.msb_right = 0; */ - switch (par->bpp) { + switch (var->bits_per_pixel) { case 16: /* RGB 565 LfbMode 0 */ var->red.length = 5; var->green.length = 6; @@ -746,309 +611,311 @@ static int sstfb_encode_var (struct fb_var_screeninfo *var, break; #endif default: - eprintk ("bug line %d: bad depth '%u'\n", __LINE__, par->bpp); - break; + BUG(); + return -EINVAL; } return 0; } -/* - * Frame buffer API - */ - -static int sstfb_open(struct fb_info *info, int user) +static int sstfb_set_par(struct fb_info *info) { - f_dprintk("sstfb_open(user: %d)\n",user); - return 0; -} + struct sstfb_par *par = (struct sstfb_par *) info->par; + u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0; + struct pci_dev *sst_dev = par->dev; + unsigned int freq; + int ntiles; -static int sstfb_release(struct fb_info *info, int user) -{ - f_dprintk("sstfb_release(user: %d)\n",user); - return 0; -} + par->hSyncOff = info->var.xres + info->var.right_margin + info->var.left_margin; -static int sstfb_get_fix(struct fb_fix_screeninfo *fix, - int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) + par->yDim = info->var.yres; + par->vSyncOn = info->var.vsync_len; + par->vSyncOff = info->var.yres + info->var.lower_margin + info->var.upper_margin; + par->vBackPorch = info->var.upper_margin; - struct fb_var_screeninfo *var; + /* We need par->pll */ + sst_calc_pll(PICOS2KHZ(info->var.pixclock), &freq, &par->pll); - f_dprintk("sstfb_get_fix(con: %d)\n",con); - if (con == -1) - sstfb_encode_var(var, &sst_info->current_par, sst_info); - else - var = &fb_display[con].var; + if (info->var.vmode & FB_VMODE_INTERLACED) + par->vBackPorch += (par->vBackPorch % 2); + if (info->var.vmode & FB_VMODE_DOUBLE) { + par->vBackPorch <<= 1; + par->yDim <<=1; + par->vSyncOn <<=1; + par->vSyncOff <<=1; + } - strcpy(fix->id, sst_info->info.modename); - /* lfb phys address = membase + 4Mb */ - fix->smem_start = sst_info->video.base; - fix->smem_len = sst_info->video.len; + if (IS_VOODOO2(par)) { + /* voodoo2 has 32 pixel wide tiles , BUT stange things + happen with odd number of tiles */ + par->tiles_in_X= (info->var.xres + 63 ) / 64 * 2; + } else { + /* voodoo1 has 64 pixels wide tiles. */ + par->tiles_in_X= (info->var.xres + 63 ) / 64; + } - fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = FB_VISUAL_TRUECOLOR; - /* - * According to the specs, the linelength must be of 1024 *pixels*. - * and the 24bpp mode is in fact a 32 bpp mode. - */ - fix->line_length = (var->bits_per_pixel == 16) ? 2048 : 4096 ; - return 0; -#undef sst_info -} + f_dprintk("sst_set_par(%dx%d)\n", info->var.xres, info->var.yres); + f_ddprintk("var->hsync_len hSyncOff var->vsync_len vSyncOff\n"); + f_ddprintk("%-7d %-8d %-7d %-8d\n", + info->var.hsync_len, par->hSyncOff, + par->vSyncOn, par->vSyncOff); + f_ddprintk("var->left_margin var->upper_margin var->xres var->yres Freq\n"); + f_ddprintk("%-10d %-10d %-4d %-4d %-8d\n", + info->var.left_margin, var->upper_margin, + info->var.xres, info->var.yres, par->freq); -static int sstfb_get_var(struct fb_var_screeninfo *var, - int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) - f_dprintk("sstfb_get_var(con: %d)\n",con); - if (con == -1) - sstfb_encode_var(var, &sst_info->current_par, sst_info); - else - *var = fb_display[con].var; - print_var(var, "var"); - return 0; -#undef sst_info - } + sst_write(NOPCMD, 0); + sst_wait_idle(); + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); + sst_set_bits(FBIINIT1, VIDEO_RESET); + sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); + sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); + sst_wait_idle(); -static int sstfb_set_var(struct fb_var_screeninfo *var, - int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) + /*sst_unset_bits (FBIINIT0, FBI_RESET); / reenable FBI ? */ - struct sstfb_par par; - struct display *display; - int err; - int old_bpp,old_xres,old_yres; - - f_dprintk("sstfb_set_var(con: %d)\n",con); - f_ddprintk("xres yres vxres vyres bpp activate\n"); - f_ddprintk("%-4d %-4d %-5d %-5d %-3d %#-8x\n", - var->xres,var->yres,var->xres_virtual,var->yres_virtual, - var->bits_per_pixel,var->activate); - if (con < 0) - display = &sst_info->disp; - else - display = &fb_display[con]; + sst_write(BACKPORCH, par->vBackPorch << 16 | (info->var.left_margin - 2)); + sst_write(VIDEODIMENSIONS, par->yDim << 16 | (info->var.xres - 1)); + sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (info->var.hsync_len - 1)); + sst_write(VSYNC, par->vSyncOff << 16 | par->vSyncOn); - if ((err = sstfb_decode_var(var, &par, sst_info))) - return err; - sstfb_encode_var (var, &par, sst_info); + fbiinit2=sst_read(FBIINIT2); + fbiinit3=sst_read(FBIINIT3); - switch (var->activate & FB_ACTIVATE_MASK) { - case FB_ACTIVATE_TEST: - return 0; - case FB_ACTIVATE_NXTOPEN: - case FB_ACTIVATE_NOW: - break; - default: - return -EINVAL; + /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */ + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + PCI_EN_INIT_WR | PCI_REMAP_DAC ); + + par->dac_sw.set_vidmod(info, info->var.bits_per_pixel); + + /* set video clock */ + par->dac_sw.set_pll(info, &par->pll, VID_CLOCK); + + /* disable fbiinit2/3 remap */ + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + PCI_EN_INIT_WR); + + /* restore fbiinit2/3 */ + sst_write(FBIINIT2,fbiinit2); + sst_write(FBIINIT3,fbiinit3); + + fbiinit1 = (sst_read(FBIINIT1) & VIDEO_MASK) + | EN_DATA_OE + | EN_BLANK_OE + | EN_HVSYNC_OE + | EN_DCLK_OE +/* | (15 << TILES_IN_X_SHIFT)*/ + | SEL_INPUT_VCLK_2X +/* | (2 << VCLK_2X_SEL_DEL_SHIFT) + | (2 << VCLK_DEL_SHIFT)*/; +/* try with vclk_in_delay =0 (bits 29:30) , vclk_out_delay =0 (bits(27:28) + in (near) future set them accordingly to revision + resolution (cf glide) + first understand what it stands for :) + FIXME: there are some artefacts... check for the vclk_in_delay + lets try with 6ns delay in both vclk_out & in... + doh... they're still there :\ +*/ + + ntiles = par->tiles_in_X; + if (IS_VOODOO2(par)) { + fbiinit1 |= ((ntiles & 0x20) >> 5) << TILES_IN_X_MSB_SHIFT + | ((ntiles & 0x1e) >> 1) << TILES_IN_X_SHIFT ; +/* as the only value of importance for us in fbiinit6 is tiles in X (lsb), + and as reading fbinit 6 will return crap (see FBIINIT6_DEFAULT) we just + write our value. BTW due to the dac unable to read odd number of tiles, this + field is always null ... */ + fbiinit6 = (ntiles & 0x1) << TILES_IN_X_LSB_SHIFT; } - old_xres = display->var.xres; - old_yres = display->var.yres; - old_bpp = display->var.bits_per_pixel; - display->var = *var; - - if ((old_xres != var->xres) || (old_yres != var->yres) - || (old_bpp != var->bits_per_pixel)) { - /* 2-3 lignes redondantes avec get_fix */ - display->screen_base = (char *) sst_info->video.vbase; - display->visual = FB_VISUAL_TRUECOLOR; - display->type = FB_TYPE_PACKED_PIXELS; - display->type_aux = 0; - display->ypanstep = 0; - display->ywrapstep = 0; - display->line_length = (var->bits_per_pixel==16) ? 2048 : 4096; - display->inverse = 0; - switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_CFB16 - case 16: - display->dispsw = &fbcon_cfb16; - display->dispsw_data = sst_info->fbcon_cmap.cfb16; - break; -#endif + else + fbiinit1 |= ntiles << TILES_IN_X_SHIFT; + + switch (info->var.bits_per_pixel) { + case 16: + fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL; + break; #ifdef EN_24_32_BPP -#if defined (FBCON_HAS_CFB24) || defined (FBCON_HAS_CFB32 ) - case 24: /*24bpp non packed <=> 32 bpp */ - case 32: - display->dispsw = &fbcon_cfb32; - display->dispsw_data = sst_info->fbcon_cmap.cfb32; - break; -#endif + case 24: + case 32: +/* orig sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP); */ + fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP; + break; #endif - default: - display->dispsw = &fbcon_dummy; - break; - } - display->scrollmode = SCROLL_YREDRAW; - if (sst_info->info.changevar) { - v_dprintk("fb_info.changevar(con: %d)\n", con); - (*sst_info->info.changevar)(con); - v_dprintk("fb_info.changevar: done \n"); - } else { - v_dprintk("fb_info.changevar() == NULL . \n"); - } + default: + dprintk("bug line %d: bad depth '%u'\n", __LINE__, + info->var.bits_per_pixel ); + return 0; + break; } - - if ((con == -1) || (con==sst_info->currcon)) { - sstfb_set_par (&par, sst_info); + sst_write(FBIINIT1, fbiinit1); + if (IS_VOODOO2(par)) { + sst_write(FBIINIT6, fbiinit6); + fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ; + if (info->var.vmode & FB_VMODE_INTERLACED) + fbiinit5 |= INTERLACE; + if (info->var.vmode & FB_VMODE_DOUBLE ) + fbiinit5 |= VDOUBLESCAN; + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + fbiinit5 |= HSYNC_HIGH; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + fbiinit5 |= VSYNC_HIGH; + sst_write(FBIINIT5, fbiinit5); } - print_var(var, "var"); - print_var(&display->var, "&display->var"); + sst_wait_idle(); + sst_unset_bits(FBIINIT1, VIDEO_RESET); + sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET); + sst_set_bits(FBIINIT2, EN_DRAM_REFRESH); +/* disables fbiinit writes */ + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR); - if (old_bpp != var->bits_per_pixel) { - if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) - return err; - sstfb_install_cmap(con, info); + /* set lfbmode : set mode + front buffer for reads/writes + + disable pipeline */ + switch (info->var.bits_per_pixel) { + case 16: + lfbmode = LFB_565; + break; +#ifdef EN_24_32_BPP + case 24: + lfbmode = LFB_888; + break; + case 32: + lfbmode = LFB_8888; + break; +#endif + default: + dprintk("bug line %d: bad depth '%u'\n", __LINE__, + info->var.bits_per_pixel ); + return 0; + break; } - return 0; -#undef sst_info -} - - -static int sstfb_set_cmap(struct fb_cmap *cmap, int kspc, - int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) - struct display *d = (con<0) ? info->disp : fb_display + con; +#if defined(__BIG_ENDIAN) + /* Enable byte-swizzle functionality in hardware. + * With this enabled, all our read- and write-accesses to + * the voodoo framebuffer can be done in native format, and + * the hardware will automatically convert it to little-endian. + * (tested on HP-PARISC, deller@gmx.de) */ + lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR | + LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD ); +#endif + + if (clipping) { + sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE); + /* + * Set "clipping" dimensions. If clipping is disabled and + * writes to offscreen areas of the framebuffer are performed, + * the "behaviour is undefined" (_very_ undefined) - Urs + */ + /* btw, it requires enabling pixel pipeline in LFBMODE . + off screen read/writes will just wrap and read/print pixels + on screen. Ugly but not that dangerous */ - f_dprintk("sstfb_set_cmap\n"); - f_ddprintk("con: %d, currcon: %d, d->cmap.len %d\n", - con, sst_info->currcon, d->cmap.len); + f_ddprintk("setting clipping dimensions 0..%d, 0..%d\n", + info->var.xres - 1, par->yDim - 1); - if (d->cmap.len != 16 ) { /* or test if cmap.len == 0 ? */ - int err; - err = fb_alloc_cmap(&d->cmap, 16, 0); /* cmap size=16 */ - if (err) return err; - } - if (con == sst_info->currcon) { - return fb_set_cmap(cmap, kspc, sstfb_setcolreg, info); + sst_write(CLIP_LEFT_RIGHT, info->var.xres ); + sst_write(CLIP_LOWY_HIGHY, par->yDim ); + sst_set_bits(FBZMODE, EN_CLIPPING | EN_RGB_WRITE); } else { - fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); + /* no clipping : direct access, no pipeline */ + sst_write(LFBMODE, lfbmode ); } - return 0; -#undef sst_info + return 1; } -static int sstfb_get_cmap(struct fb_cmap *cmap, int kspc, - int con, struct fb_info *info) +static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { -#define sst_info ((struct sstfb_info *) info) - f_dprintk("sstfb_get_cmap\n"); - f_ddprintk("con %d, curcon %d, cmap.len %d\n", - con, sst_info->currcon, fb_display[con].cmap.len); - - /* FIXME: check if con = -1 ? cf sstfb_set_cmap... */ - if (con == sst_info->currcon) - return fb_get_cmap(cmap, kspc, sstfb_getcolreg, info); - else if (fb_display[con].cmap.len) - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap( - fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); - return 0; -#undef sst_info -} + u32 col; -/* TODO */ -static int sstfb_pan_display(struct fb_var_screeninfo *var, - int con, struct fb_info *info) -{ - f_dprintk("sstfb_pan_display\n"); - return -EINVAL; + f_dddprintk("sstfb_setcolreg\n"); + f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n", + regno, red, green, blue, transp); + if (regno >= 16) return 1; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + transp >>= (16 - info->var.transp.length); + col = (red << info->var.red.offset) + | (green << info->var.green.offset) + | (blue << info->var.blue.offset) + | (transp << info->var.transp.offset); + return 0; } static int sstfb_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg, int con, - struct fb_info *info) + u_int cmd, u_long arg, struct fb_info *info ) { -#define sst_info ((struct sstfb_info *) info) -#if (SST_DEBUG_IOCTL >0) - int i; + struct sstfb_par *par = (struct sstfb_par *) info->par; + struct pci_dev *sst_dev = par->dev; + u32 fbiinit0, tmp, val; u_long p; - u32 tmp; - u32 fbiinit0; - struct pci_dev * sst_dev = sst_info->dev; -#endif f_dprintk("sstfb_ioctl(%x)\n", cmd); -#if (SST_DEBUG_IOCTL >0) switch (cmd) { -# if (SST_DEBUG_VAR >0) -/* tmp ioctl : dumps fb_display[0-5] */ - case _IO('F', 0xdb): /* 0x46db */ - f_dprintk("dumping fb_display[0-5].var\n"); - for (i = 0 ; i< 6 ; i++) { - print_var(&fb_display[i].var, "var(%d)", i); - } - return 0; -# endif /* (SST_DEBUG_VAR >0) */ -/* fills the lfb up to *(u32*)arg */ + + /* fills lfb with #arg pixels */ case _IOW('F', 0xdc, u32): /* 0x46dc */ - if (*(u32*)arg > 0x400000 ) - *(u32*) arg = 0x400000; - f_dprintk("filling %#x \n", *(u32*)arg); - for (p = 0 ; p < *(u32*)arg; p+=2) - writew( p >> 6 , sst_info->video.vbase + p); + if (copy_from_user(&val, (void *) arg, sizeof(val))) + return -EFAULT; + if (val > info->fix.smem_len) + val = info->fix.smem_len; + f_dprintk("filling %#x \n", val); + for (p = 0 ; p < val; p+=2) + writew( p >> 6 , info->screen_base + p); return 0; -/* change VGA pass_through */ + + /* change VGA pass_through mode */ case _IOW('F', 0xdd, u32): /* 0x46dd */ + if (copy_from_user(&val, (void *) arg, sizeof(val))) + return -EFAULT; f_dprintk("switch VGA pass-through\n"); pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp | PCI_EN_INIT_WR ); fbiinit0 = sst_read (FBIINIT0); - if (* (u32*)arg) { + if (val) { sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH); - iprintk ( "Disabling VGA pass-through\n"); + iprintk( "Disabling VGA pass-through\n"); } else { sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH); - iprintk ( "Enabling VGA pass-through\n"); + iprintk( "Enabling VGA pass-through\n"); } pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); return 0; + + /* draw test image */ case _IO('F', 0xde): /* 0x46de */ f_dprintk("test color display\n"); - f_ddprintk("currcon: %d, bpp %d\n", sst_info->currcon, - sst_info->current_par.bpp); - memset_io(sst_info->video.vbase, 0, sst_info->video.len); - switch (sst_info->current_par.bpp) { -/* FIXME broken : if we call this ioctl from a tty not bound to the fb, we use its depth and not the current one ... */ - case 16: - sstfb_test16(sst_info); + f_ddprintk("bpp %d\n", + sst_info->par.bpp); + memset_io(info->screen_base, 0, info->fix.smem_len); + switch (info->var.bits_per_pixel) { + case 16: + sstfb_test16(info); break; -# ifdef EN_24_32_BPP - case 24: - case 32: - sstfb_test32(sst_info); +#ifdef EN_24_32_BPP + case 24: + case 32: + sstfb_test32(info); break; -# endif - default: - dprintk("bug line %d: bad depth '%u'\n", __LINE__, - sst_info->current_par.bpp); - } - return 0; - case _IO('F', 0xdf): /* 0x46db */ - Dump_regs; +#endif + default: + BUG(); + } return 0; } -#endif /* (SST_DEBUG_IOCTL >0) */ return -EINVAL; -#undef sst_info } - /* * Low level routines */ /* get lfb size */ -static int __devinit sst_get_memsize(struct sstfb_info *sst_info, u_long *memsize) +static int __devinit sst_get_memsize(struct fb_info *info, u_long *memsize) { - u_long fbbase_virt = sst_info->video.vbase; + u_long fbbase_virt = (ulong) info->screen_base; f_dprintk("sst_get_memsize\n"); /* force memsize */ @@ -1084,62 +951,20 @@ static int __devinit sst_get_memsize(struct sstfb_info *sst_info, u_long *memsiz } -/* - * wait for the fbi chip. ASK: what happens if the fbi is stuck ? - * - * the FBI is supposed to be ready if we receive 5 time - * in a row a "idle" answer to our requests +/* + * DAC detection routines */ -static int __sst_wait_idle(u_long vbase) -{ - int count = 0; - - f_ddprintk("sst_wait_idle\n"); - while(1) { - if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) { - f_dddprintk("status: busy\n"); -/* FIXME basicaly, this is a busy wait. maybe not that good. oh well; this is a small loop after all ...*/ - count = 0; - } else { - count++; - f_dddprintk("status: idle(%d)\n", count); - } - if (count >= 5) return 1; -//XXX do something to avoid hanging the machine if the voodoo is out - } -} - -/* - * detect dac type - * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset, - * dram refresh disabled, FbiInit remaped. - * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ... - */ -static int __devinit sst_detect_dactype(struct sstfb_info * sst_info) -{ - int ret=0,i; - f_dprintk("sst_detect_dactype\n"); - for (i=0; i< sizeof(dacs)/sizeof(dacs[0]) ; i++) { - ret = dacs[i].detect(sst_info); - if (ret) break; - } - if (!ret) - return 0; - f_dprintk("found %s\n", dacs[i].name); - sst_info->dac_sw=dacs[i]; - return 1; -} - /* fbi should be idle, and fifo emty and mem disabled */ /* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */ -static int __devinit sst_detect_att(struct sstfb_info * sst_info) +static int __devinit sst_detect_att(struct fb_info *info) { + struct sstfb_par *par = (struct sstfb_par *) info->par; int i, mir, dir; f_dprintk("sst_detect_att\n"); - for (i = 0; i<3; i++) { + for (i=0; i<3; i++) { sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* read 4 times RMR */ sst_dac_read(DACREG_RMR); @@ -1159,8 +984,9 @@ static int __devinit sst_detect_att(struct sstfb_info * sst_info) return 0; } -static int __devinit sst_detect_ti(struct sstfb_info * sst_info) +static int __devinit sst_detect_ti(struct fb_info *info) { + struct sstfb_par *par = (struct sstfb_par *) info->par; int i, mir, dir; f_dprintk("sst_detect_ti\n"); @@ -1195,11 +1021,13 @@ static int __devinit sst_detect_ti(struct sstfb_info * sst_info) * touched... * is it realy safe ? how can i reset this ramdac ? geee... */ -static int __devinit sst_detect_ics(struct sstfb_info * sst_info) +static int __devinit sst_detect_ics(struct fb_info *info) { - int i; + struct sstfb_par *par = (struct sstfb_par *) info->par; int m_clk0_1, m_clk0_7, m_clk1_b; int n_clk0_1, n_clk0_7, n_clk1_b; + int i; + f_dprintk("sst_detect_ics\n"); for (i = 0; i<5; i++ ) { sst_dac_write(DACREG_ICS_PLLRMA, 0x1); /* f1 */ @@ -1224,68 +1052,19 @@ static int __devinit sst_detect_ics(struct sstfb_info * sst_info) return 0; } -/* compute the m,n,p , returns the real freq - * (ics datasheet : N <-> N1 , P <-> N2) - * - * Fout= Fref * (M+2)/( 2^P * (N+2)) - * we try to get close to the asked freq - * with P as high, and M as low as possible - * range: - * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63 - * ics : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31 - * we'll use the lowest limitation, should be precise enouth - */ -static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t) -{ - int m, m2, n, p, best_err, fout; - int best_n=-1; - int best_m=-1; - - f_dprintk("sst_calc_pll(%dKhz)\n", freq); - best_err = freq; - p=3; - /* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/ - while (((1 << p) * freq > VCO_MAX) && (p >= 0)) - p--; - if (p == -1) - return -EINVAL; - for (n = 1; n < 32; n++) { - /* calc 2 * m so we can round it later*/ - m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ; - - m = (m2 % 2 ) ? m2/2+1 : m2/2 ; - if (m >= 128) - break; - fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2)); - if ((ABS(fout - freq) < best_err) && (m > 0)) { - best_n = n; - best_m = m; - best_err = ABS(fout - freq); - /* we get the lowest m , allowing 0.5% error in freq*/ - if (200*best_err < freq) break; - } - } - if (best_n == -1) /* unlikely, but who knows ? */ - return -EINVAL; - t->p=p; - t->n=best_n; - t->m=best_m; - *freq_out=(DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2)); - f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n", - t->m, t->n, t->p, *freq_out); - return 0; -} /* * gfx, video, pci fifo should be reset, dram refresh disabled * see detect_dac */ -static int sst_set_pll_att_ti(struct sstfb_info * sst_info, const struct pll_timing *t, const int clock) +static int sst_set_pll_att_ti(struct fb_info *info, + const struct pll_timing *t, const int clock) { + struct sstfb_par *par = (struct sstfb_par *) info->par; u8 cr0, cc; - f_dprintk("sst_set_pll_att_ti\n"); + f_dprintk("sst_set_pll_att_ti\n"); /* enable indexed mode */ sst_dac_write(DACREG_WMA, 0); /* backdoor */ @@ -1335,8 +1114,10 @@ static int sst_set_pll_att_ti(struct sstfb_info * sst_info, const struct pll_tim return 1; } -static int sst_set_pll_ics(struct sstfb_info * sst_info, const struct pll_timing *t, const int clock) +static int sst_set_pll_ics(struct fb_info *info, + const struct pll_timing *t, const int clock) { + struct sstfb_par *par = (struct sstfb_par *) info->par; u8 pll_ctrl; f_dprintk("sst_set_pll_ics\n"); @@ -1373,178 +1154,9 @@ static int sst_set_pll_ics(struct sstfb_info * sst_info, const struct pll_timing return 1; } -static int sstfb_set_par(const struct sstfb_par * par, struct sstfb_info * sst_info) -{ - u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0; - int ntiles; - struct pci_dev * sst_dev = sst_info->dev; - - f_dprintk("sst_set_par(%dx%d)\n", par->xDim, par->yDim); - f_ddprintk("hSyncOn hSyncOff vSyncOn vSyncOff\n"); - f_ddprintk("%-7d %-8d %-7d %-8d\n", - par->hSyncOn, par->hSyncOff, - par->vSyncOn, par->vSyncOff); - f_ddprintk("hBackPorch vBackPorch xDim yDim Freq\n"); - f_ddprintk("%-10d %-10d %-4d %-4d %-8d\n", - par->hBackPorch, par->vBackPorch, - par->xDim, par->yDim, par->freq); - - if (!par->valid) { - BUG(); - return -1; - } - sst_write(NOPCMD, 0); - sst_wait_idle(); - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); - sst_set_bits(FBIINIT1, VIDEO_RESET); - sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); - sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); - sst_wait_idle(); - - /*sst_unset_bits (FBIINIT0, FBI_RESET); / reenable FBI ? */ - - sst_write(BACKPORCH, par->vBackPorch << 16 | (par->hBackPorch - 2)); - sst_write(VIDEODIMENSIONS, par->yDim << 16 | (par->xDim - 1)); - sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (par->hSyncOn - 1)); - sst_write(VSYNC, par->vSyncOff << 16 | par->vSyncOn); - - fbiinit2=sst_read(FBIINIT2); - fbiinit3=sst_read(FBIINIT3); - - /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, - PCI_EN_INIT_WR | PCI_REMAP_DAC ); - - sst_info->dac_sw.set_vidmod(sst_info, par->bpp); - - /* set video clock */ - sst_info->dac_sw.set_pll(sst_info, &par->pll, VID_CLOCK); - - /* disable fbiinit2/3 remap */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, - PCI_EN_INIT_WR); - - /* restore fbiinit2/3 */ - sst_write(FBIINIT2,fbiinit2); - sst_write(FBIINIT3,fbiinit3); - - fbiinit1 = (sst_read(FBIINIT1) & VIDEO_MASK) - | EN_DATA_OE - | EN_BLANK_OE - | EN_HVSYNC_OE - | EN_DCLK_OE -/* | (15 << TILES_IN_X_SHIFT)*/ - | SEL_INPUT_VCLK_2X -/* | (2 << VCLK_2X_SEL_DEL_SHIFT) - | (2 << VCLK_DEL_SHIFT)*/; -/* try with vclk_in_delay =0 (bits 29:30) , vclk_out_delay =0 (bits(27:28) - in (near) future set them accordingly to revision + resolution (cf glide) - first understand what it stands for :) - FIXME: there are some artefacts... check for the vclk_in_delay - lets try with 6ns delay in both vclk_out & in... - doh... they're still there :\ -*/ - - ntiles = par->tiles_in_X; - if (IS_VOODOO2(sst_info)) { - fbiinit1 |= ((ntiles & 0x20) >> 5) << TILES_IN_X_MSB_SHIFT - | ((ntiles & 0x1e) >> 1) << TILES_IN_X_SHIFT ; -/* as the only value of importance for us in fbiinit6 is tiles in X (lsb), - and as reading fbinit 6 will return crap (see FBIINIT6_DEFAULT) we just - write our value. BTW due to the dac unable to read odd number of tiles, this - field is always null ... */ - fbiinit6 = (ntiles & 0x1) << TILES_IN_X_LSB_SHIFT; - } - else - fbiinit1 |= ntiles << TILES_IN_X_SHIFT; - - switch(par->bpp) { - case 16: - fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL; - break; -#ifdef EN_24_32_BPP - case 24: - case 32: -/* orig sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP); */ - fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP; - break; -#endif - default: - dprintk("bug line %d: bad depth '%u'\n", __LINE__, - par->bpp ); - return 0; - break; - } - sst_write(FBIINIT1, fbiinit1); - if (IS_VOODOO2(sst_info)) { - sst_write(FBIINIT6, fbiinit6); - fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ; - if (par->vmode & FB_VMODE_INTERLACED) - fbiinit5 |= INTERLACE; - if (par->vmode & FB_VMODE_DOUBLE ) - fbiinit5 |= VDOUBLESCAN; - if (par->sync & FB_SYNC_HOR_HIGH_ACT) - fbiinit5 |= HSYNC_HIGH; - if (par->sync & FB_SYNC_VERT_HIGH_ACT) - fbiinit5 |= VSYNC_HIGH; - sst_write(FBIINIT5, fbiinit5); - } - sst_wait_idle(); - sst_unset_bits(FBIINIT1, VIDEO_RESET); - sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET); - sst_set_bits(FBIINIT2, EN_DRAM_REFRESH); -/* disables fbiinit writes */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR); - - /* set lfbmode : set mode + front buffer for reads/writes - + disable pipeline + disable byte swapping */ - switch(par->bpp) { - case 16: - lfbmode = LFB_565; - break; -#ifdef EN_24_32_BPP - case 24: - lfbmode = LFB_888; - break; - case 32: - lfbmode = LFB_8888; - break; -#endif - default: - dprintk("bug line %d: bad depth '%u'\n", __LINE__, - par->bpp ); - return 0; - break; - } - - if (clipping) { - sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE); - /* - * Set "clipping" dimensions. If clipping is disabled and - * writes to offscreen areas of the framebuffer are performed, - * the "behaviour is undefined" (_very_ undefined) - Urs - */ - /* btw, it requires enabling pixel pipeline in LFBMODE . - off screen read/writes will just wrap and read/print pixels - on screen. Ugly but not that dangerous */ - - f_ddprintk("setting clipping dimensions 0..%d, 0..%d\n", - par->xDim-1, par->yDim-1); - - sst_write(CLIP_LEFT_RIGHT, par->xDim ); - sst_write(CLIP_LOWY_HIGHY, par->yDim ); - sst_set_bits(FBZMODE, EN_CLIPPING | EN_RGB_WRITE); - } else { - /* no clipping : direct access, no pipeline */ - sst_write(LFBMODE, lfbmode ); - } - - sst_info->current_par = *par ; - return 1; -} - -static void sst_set_vidmod_att_ti(struct sstfb_info * sst_info, const int bpp) +static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp) { + struct sstfb_par *par = (struct sstfb_par *) info->par; u8 cr0; f_dprintk("sst_set_vidmod_att_ti(bpp: %d)\n", bpp); @@ -1579,8 +1191,10 @@ static void sst_set_vidmod_att_ti(struct sstfb_info * sst_info, const int bpp) } } -static void sst_set_vidmod_ics(struct sstfb_info * sst_info, const int bpp) +static void sst_set_vidmod_ics(struct fb_info *info, const int bpp) { + struct sstfb_par *par = (struct sstfb_par *) info->par; + f_dprintk("sst_set_vidmod_ics(bpp: %d)\n", bpp); switch(bpp) { case 16: @@ -1598,18 +1212,58 @@ static void sst_set_vidmod_ics(struct sstfb_info * sst_info, const int bpp) } } -static int __devinit sst_init(struct sstfb_info *sst_info) +/* + * detect dac type + * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset, + * dram refresh disabled, FbiInit remaped. + * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ... + */ + + +static struct dac_switch dacs[] __devinitdata = { + { .name = "TI TVP3409", + .detect = sst_detect_ti, + .set_pll = sst_set_pll_att_ti, + .set_vidmod = sst_set_vidmod_att_ti }, + + { .name = "AT&T ATT20C409", + .detect = sst_detect_att, + .set_pll = sst_set_pll_att_ti, + .set_vidmod = sst_set_vidmod_att_ti }, + { .name = "ICS ICS5342", + .detect = sst_detect_ics, + .set_pll = sst_set_pll_ics, + .set_vidmod = sst_set_vidmod_ics }, +}; + +static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par) +{ + int ret = 0,i; + + f_dprintk("sst_detect_dactype\n"); + for (i=0; i<sizeof(dacs)/sizeof(dacs[0]); i++) { + ret = dacs[i].detect(info); + if (ret) break; + } + if (!ret) + return 0; + f_dprintk("found %s\n", dacs[i].name); + par->dac_sw = dacs[i]; + return 1; +} + +/* + * Internal Routines + */ +static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par) { + u32 fbiinit0, fbiinit1, fbiinit4; + struct pci_dev *dev = par->dev; struct pll_timing gfx_timings; struct sst_spec * spec; - struct pci_dev * sst_dev = sst_info->dev; int Fout; - u32 fbiinit0, fbiinit1, fbiinit4; - dprintk("sst_init\n"); //XXX - Dump_regs; //XXX - - spec = &voodoo_spec[sst_info->type]; + spec = &voodoo_spec[par->type]; f_dprintk("sst_init\n"); f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " " fbiinit6\n"); @@ -1617,10 +1271,10 @@ static int __devinit sst_init(struct sstfb_info *sst_info) sst_read(FBIINIT0), sst_read(FBIINIT1), sst_read(FBIINIT2), sst_read(FBIINIT3), sst_read(FBIINIT4), sst_read(FBIINIT6)); /* disable video clock */ - pci_write_config_dword(sst_dev, PCI_VCLK_DISABLE,0); + pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); /* enable writing to init registers ,disable pci fifo*/ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); /* reset video */ sst_set_bits(FBIINIT1, VIDEO_RESET); sst_wait_idle(); @@ -1639,29 +1293,29 @@ static int __devinit sst_init(struct sstfb_info *sst_info) sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_wait_idle(); /* remap fbinit2/3 to dac */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); /* detect dac type */ - if (!sst_detect_dactype(sst_info)) { + if (!sst_detect_dactype(info, par)) { eprintk("Unknown dac type\n"); - //FIXME watch it : we are not in a safe state , bad bad bad . + //FIXME watch it : we are not in a safe state, bad bad bad . return 0; } /* set graphic clock */ - sst_info->gfx_clock = spec->default_gfx_clock; + par->gfx_clock = spec->default_gfx_clock; if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { - iprintk ("Using supplied graphic freq : %dMHz\n", gfxclk); - sst_info->gfx_clock = gfxclk *1000; + iprintk("Using supplied graphic freq : %dMHz\n", gfxclk); + par->gfx_clock = gfxclk *1000; } else if (gfxclk) { wprintk ("You fool, %dMhz is way out of spec! Using default\n", gfxclk); } - sst_calc_pll(sst_info->gfx_clock, &Fout, &gfx_timings); - sst_info->dac_sw.set_pll(sst_info, &gfx_timings, GFX_CLOCK); + sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings); + par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); /* disable fbiinit remap */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR| PCI_EN_FIFO_WR ); /* defaults init registers */ /* FbiInit0: unreset gfx, unreset fifo */ @@ -1689,42 +1343,42 @@ static int __devinit sst_init(struct sstfb_info *sst_info) sst_wait_idle(); sst_write(FBIINIT4, fbiinit4); sst_wait_idle(); - if (IS_VOODOO2(sst_info)) { + if (IS_VOODOO2(par)) { sst_write(FBIINIT6, FBIINIT6_DEFAULT); sst_wait_idle(); } - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR ); - pci_write_config_dword(sst_dev, PCI_VCLK_ENABLE, 0); - + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR ); + pci_write_config_dword(dev, PCI_VCLK_ENABLE, 0); return 1; } -static void __devexit sst_shutdown(struct sstfb_info *sst_info) +static void __devexit sst_shutdown(struct fb_info *info) { - struct pci_dev * sst_dev = sst_info->dev; + struct sstfb_par *par = (struct sstfb_par *) info->par; + struct pci_dev *dev = par->dev; struct pll_timing gfx_timings; int Fout; f_dprintk("sst_shutdown\n"); /* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_set_bits(FBIINIT1, VIDEO_RESET | EN_BLANKING); sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_wait_idle(); - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); /*set 20Mhz gfx clock */ sst_calc_pll(20000, &Fout, &gfx_timings); - sst_info->dac_sw.set_pll(sst_info, &gfx_timings, GFX_CLOCK); + par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); /* TODO maybe shutdown the dac, vrefresh and so on... */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | EN_VGA_PASSTHROUGH); - pci_write_config_dword(sst_dev, PCI_VCLK_DISABLE,0); + pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct at the beginining ? */ - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, 0); + pci_write_config_dword(dev, PCI_INIT_ENABLE, 0); } @@ -1769,35 +1423,30 @@ int __init sstfb_setup(char *options) else if (!strncmp(this_opt, "dev:",4)) dev=simple_strtoul (this_opt+4, NULL, 0); else - mode_option=this_opt; + mode_option = this_opt; } return 0; } -int __devinit sstfb_init(void) -{ - f_dprintk("sstfb_init\n"); - dprintk("Compile date: "__DATE__" "__TIME__"\n"); - return pci_module_init(&sstfb_driver); -} - -void __devexit sstfb_exit(void) -{ - f_dprintk("sstfb_exit\n"); - pci_unregister_driver(&sstfb_driver); -} - -#ifdef MODULE -module_init(sstfb_init); -module_exit(sstfb_exit); -#endif +static struct fb_ops sstfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = sstfb_check_var, + .fb_set_par = sstfb_set_par, + .fb_setcolreg = sstfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_ioctl = sstfb_ioctl, +}; static int __devinit sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct fb_var_screeninfo var; - struct sstfb_info * sst_info; - struct sst_spec * spec; - int tmp,err; + struct sstfb_par *default_par; + struct fb_fix_screeninfo *fix; + struct sst_spec *spec; + struct fb_info *info; + int err; f_dprintk("sstfb_probe\n"); /* dev > 0 the device is not the one asked for. skip */ @@ -1805,268 +1454,269 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, const struct pci_device_i /* dev == -1 we already inited the asked device. skip */ /* dev < -1 init all devices. including this one. init */ if ((dev == -1 ) || (dev-- > 0)) - return -1; + return -ENODEV; if ((err=pci_enable_device(pdev))) { eprintk("cannot enable device\n"); return err; } - sst_info = (struct sstfb_info*)kmalloc(sizeof(*sst_info), GFP_KERNEL); - if (!sst_info) - goto fail_kmalloc; - pci_set_drvdata(pdev, sst_info); - sst_info->type = id->driver_data; - spec = &voodoo_spec[sst_info->type]; + info = kmalloc(sizeof(struct fb_info) + sizeof(struct sstfb_par), GFP_KERNEL); + if (!info) + return -ENOMEM; + default_par = (struct sstfb_par *) (info + 1); + fix = &info->fix; + info->par = default_par; + + pci_set_drvdata(pdev, info); + default_par->type = id->driver_data; + spec = &voodoo_spec[default_par->type]; f_ddprintk("found device : %s\n", spec->name); - sst_info->dev = pdev; - pci_read_config_byte(pdev, PCI_REVISION_ID, &sst_info->revision); + default_par->dev = pdev; + pci_read_config_byte(pdev, PCI_REVISION_ID, &default_par->revision); - sst_info->mmio.base = pci_resource_start(pdev,0); - sst_info->video.base = sst_info->mmio.base+0x400000; + fix->mmio_start = pci_resource_start(pdev,0); + fix->smem_start = fix->mmio_start + 0x400000; - if (!request_mem_region(sst_info->mmio.base,0x400000,"sstfb MMIO")) { - eprintk ("cannot reserve mmio memory\n"); + if (!request_mem_region(fix->mmio_start, 0x400000,"sstfb MMIO")) { + eprintk("cannot reserve mmio memory\n"); goto fail_mmio_mem; } - if (!request_mem_region(sst_info->video.base,0x400000,"sstfb FB")) { - eprintk ("cannot reserve fb memory\n"); + if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) { + eprintk("cannot reserve fb memory\n"); goto fail_fb_mem; } - sst_info->mmio.vbase = (u_long) ioremap_nocache(sst_info->mmio.base, 0x400000); - if (!sst_info->mmio.vbase) { + default_par->mmio_vbase = (u_long) ioremap_nocache(fix->mmio_start, 0x400000); + if (!default_par->mmio_vbase) { eprintk("cannot remap register area %#lx\n", - sst_info->mmio.base); + fix->mmio_start); goto fail_mmio_remap; } - sst_info->video.vbase = (u_long) ioremap_nocache(sst_info->video.base, 0x400000); - if (!sst_info->video.vbase) { + info->screen_base = ioremap_nocache(fix->smem_start, 0x400000); + if (!info->screen_base) { eprintk("cannot remap framebuffer %#lx\n", - sst_info->video.base); + fix->smem_start); goto fail_fb_remap; } - if(!sst_init(sst_info)) { + if(!sst_init(info, default_par)) { eprintk("Init failed\n"); goto fail; } - sst_get_memsize(sst_info, &sst_info->video.len); - strncpy(sst_info->info.modename, spec->name, 16); + sst_get_memsize(info, (unsigned long *) &fix->smem_len); + strncpy(fix->id, spec->name, sizeof(fix->id)); - iprintk("%s with %s dac\n", sst_info->info.modename, sst_info->dac_sw.name); + iprintk("%s with %s dac\n", fix->id, default_par->dac_sw.name); iprintk("framebuffer at %#lx, mapped to %#lx," - " size %ldMb\n", - sst_info->video.base, sst_info->video.vbase, - sst_info->video.len >> 20); - - f_ddprintk("revision: %d\n", sst_info->revision); - f_ddprintk("regbase_virt: %#lx\n", sst_info->mmio.vbase); - f_ddprintk("membase_phys: %#lx\n", sst_info->video.base); - f_ddprintk("fbbase_virt: %#lx\n", sst_info->video.vbase); - - sst_info->info.node = -1 ; - sst_info->info.flags = FBINFO_FLAG_DEFAULT; - sst_info->info.fbops = &sstfb_ops; - sst_info->info.disp = &sst_info->disp; - sst_info->info.changevar = NULL; - sst_info->info.switch_con = &sstfbcon_switch; - sst_info->info.updatevar = &sstfbcon_updatevar; - sst_info->info.blank = &sstfbcon_blank; - - tmp=0; - var = sstfb_default; - if ( mode_option && - fb_find_mode(&var, &sst_info->info, mode_option, - NULL, 0, NULL, 16)) { - if (sstfb_set_var(&var, -1, &sst_info->info)) { - eprintk("can't set supplied video mode. Using default\n"); - var = sstfb_default; - } else { - /* set the new default */ - sstfb_default = var; - tmp=1; /* no need to set the mode. */ - } - } - - if (!tmp && sstfb_set_var(&var, -1, &sst_info->info)) { + " size %dMb\n", + fix->smem_start, (unsigned long) info->screen_base, + fix->smem_len >> 20); + + f_ddprintk("revision: %d\n", default_par->revision); + f_ddprintk("regbase_virt: %#lx\n", default_par->mmio_vbase); + f_ddprintk("membase_phys: %#lx\n", fix->smem_start); + f_ddprintk("fbbase_virt: %#lx\n", info->screen_base); + + info->node = NODEV; + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &sstfb_ops; + + fix->mmio_len = 0x400000; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->accel = FB_ACCEL_NONE; /* FIXME */ + /* + * According to the specs, the linelength must be of 1024 *pixels*. + * and the 24bpp mode is in fact a 32 bpp mode. + */ + fix->line_length= 2048; /* default value, for 24 or 32bit: 4096*/ + + if ( mode_option && + fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) { + eprintk("can't set supplied video mode. Using default\n"); + info->var = sstfb_default; + } else + info->var = sstfb_default; + + if (sstfb_check_var(&info->var, info)) { eprintk("can't set default video mode.\n"); goto fail; } - /*clear fb */ - memset_io(sst_info->video.vbase, 0, sst_info->video.len); - /* print some squares ... */ - sstfb_test16(sst_info); /* FIXME this is only for 16bpp */ + + fb_alloc_cmap(&info->cmap, 16, 0); /* register fb */ - if (register_framebuffer(&sst_info->info) < 0) { + if (register_framebuffer(info) < 0) { eprintk("can't register framebuffer.\n"); goto fail; } printk(KERN_INFO "fb%d: %s frame buffer device\n", - minor(sst_info->info.node),sst_info->info.modename); + minor(info->node), fix->id); + return 0; fail: - iounmap((void *)sst_info->video.base); + iounmap(info->screen_base); fail_fb_remap: - iounmap((void *)sst_info->mmio.base); + iounmap((void *)default_par->mmio_vbase); fail_mmio_remap: - release_mem_region(sst_info->video.base,0x400000); + release_mem_region(fix->smem_start, 0x400000); fail_fb_mem: - release_mem_region(sst_info->mmio.base,0x400000); + release_mem_region(fix->mmio_start, 0x400000); fail_mmio_mem: - kfree(sst_info); -fail_kmalloc: + kfree(info); return -ENXIO; /* no voodoo detected */ } static void __devexit sstfb_remove(struct pci_dev *pdev) { - struct sstfb_info * sst_info; + struct sstfb_par *par; + struct fb_info *info; f_dprintk("sstfb_remove\n"); - sst_info=pci_get_drvdata(pdev); - sst_shutdown(sst_info); - - unregister_framebuffer(&sst_info->info); - iounmap((void*)sst_info->video.vbase); - iounmap((void*)sst_info->mmio.vbase); - release_mem_region(sst_info->video.base,0x400000); - release_mem_region(sst_info->mmio.base,0x400000); - kfree(sst_info); + info = pci_get_drvdata(pdev); + par = (struct sstfb_par *) info->par; + + sst_shutdown(info); + unregister_framebuffer(info); + iounmap(info->screen_base); + iounmap((void*)par->mmio_vbase); + release_mem_region(info->fix.smem_start, info->fix.smem_len); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + kfree(info); } -/* - * console driver - */ -static int sstfbcon_switch(int con, struct fb_info *info) -{ -#define sst_info ((struct sstfb_info *) info) - struct sstfb_par par; - - f_dprintk("sstfbcon_switch(con: %d)\n",con); - f_ddprintk("currcon: %d\n", sst_info->currcon); - v_dprintk("currcon: %d\n", sst_info->currcon); +static struct pci_device_id sstfb_id_tbl[] __devinitdata = { + { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 }, + { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 }, + { 0 }, +}; - if (sst_info->currcon >= 0) { - if (fb_display[sst_info->currcon].cmap.len) - fb_get_cmap(&fb_display[sst_info->currcon].cmap, 1, - sstfb_getcolreg, info); - } - sst_info->currcon = con; - fb_display[con].var.activate = FB_ACTIVATE_NOW; +static struct pci_driver sstfb_driver = { + .name = "sstfb", + .id_table = sstfb_id_tbl, + .probe = sstfb_probe, + .remove = __devexit_p(sstfb_remove), +}; - print_var(&fb_display[con].var, "&fb_display[con: %d].var",con); - sstfb_decode_var(&fb_display[con].var, &par, sst_info); - if (memcmp(&par,&(sst_info->current_par),sizeof(par))) { - sstfb_set_par(&par, sst_info); - } - sstfb_install_cmap(con, info); - return 0; -#undef sst_info -} -static int sstfbcon_updatevar(int con, struct fb_info *info) +int __devinit sstfb_init(void) { - f_dprintk("sstfbcon_updatevar\n"); - return -EINVAL; + f_dprintk("sstfb_init\n"); + dprintk("Compile date: "__DATE__" "__TIME__"\n"); + return pci_module_init(&sstfb_driver); } -static void sstfbcon_blank(int blank, struct fb_info *info) +void __devexit sstfb_exit(void) { - f_dprintk("sstfbcon_blank(level %d)\n", blank); + f_dprintk("sstfb_exit\n"); + pci_unregister_driver(&sstfb_driver); } +/* + * console driver + */ + +#if 1 /* print some squares on the fb (presuming 16bpp) */ -static void sstfb_test16(struct sstfb_info *sst_info) +static void sstfb_test16(struct fb_info *info) { - int i,j; + u_long fbbase_virt = (u_long) info->screen_base; u_long p; - u_long fbbase_virt = sst_info->video.vbase; + int i,j; f_dprintk("sstfb_test16\n"); - /* rect blanc 20x100+200+0 */ - for (i=0 ; i< 100; i++) { - p = fbbase_virt + 2048 *i+400; - for (j=0 ; j < 10 ; j++) { - writel( 0xffffffff, p); - p+=4; + /* draw white rect 20x100+200+0 */ + for (i=0 ; i<100; i++) { + p = fbbase_virt + 2048*i+400; + for (j=0 ; j<10 ; j++) { + writel(0xffffffff, p); + p += 4; } } - /* rect bleu 180x200+0+0 */ - for (i=0 ; i< 200; i++) { - p = fbbase_virt + 2048 *i; - for (j=0 ; j < 90 ; j++) { - writel(0x001f001f,p); - p+=4; + /* draw blue rect 180x200+0+0 */ + for (i=0 ; i<200; i++) { + p = fbbase_virt + 2048*i; + for (j=0 ; j<90 ; j++) { + writel(0x001f001f, p); + p += 4; } } - /* carre vert 40x40+100+0 */ - for (i=0 ; i< 40 ; i++) { - p = fbbase_virt + 2048 *i + 200; + /* draw green rect 40x40+100+0 */ + for (i=0 ; i<40 ; i++) { + p = fbbase_virt + 2048*i + 200; for (j=0; j <20;j++) { writel(0x07e007e0, p); - p+=4; + p += 4; } } - /*carre rouge 40x40+100+40 */ + /* draw red rect 40x40+100+40 */ for (i=0; i<40; i++) { p = fbbase_virt + 2048 * (i+40) + 200; - for (j=0; j <20;j++) { - writel( 0xf800f800, p); - p+=4; + for (j=0; j<20;j++) { + writel(0xf800f800, p); + p += 4; } } } +#endif -/* print some squares on the fb (24/32bpp) */ #ifdef EN_24_32_BPP -static void sstfb_test32(struct sstfb_info *sst_info) +/* print some squares on the fb (24/32bpp) */ +static void sstfb_test32(struct fb_info *info) { int i,j; u_long p; - u_long fbbase_virt = sst_info->video.vbase; + u_long fbbase_virt = info->screen_base; f_dprintk("sstfb_test32\n"); - /* rect blanc 20x100+200+0 */ - for (i=0 ; i< 100; i++) { + /* draw white rect 20x100+200+0 */ + for (i=0 ; i<100; i++) { p = fbbase_virt + 4096*i + 800; - for (j=0 ; j < 20 ; j++) { - writel( 0x00ffffff, p); - p+=4; + for (j=0 ; j<20; j++) { + writel(0x00ffffff, p); + p += 4; } } - /* rect bleu 180x200+0+0 */ - for (i=0 ; i< 200; i++) { - p = fbbase_virt + 4096 * i; - for (j=0 ; j < 180 ; j++) { + /* draw blue rect 180x200+0+0 */ + for (i=0 ; i<200; i++) { + p = fbbase_virt + 4096*i; + for (j=0 ; j<180; j++) { writel(0x000000ff,p); - p+=4; + p += 4; } } - /* carre vert 40x40+100+0 */ - for (i=0 ; i< 40 ; i++) { - p = fbbase_virt + 4096 *i + 400; - for (j=0; j <40;j++) { + /* draw green rect 40x40+100+0 */ + for (i=0 ; i<40 ; i++) { + p = fbbase_virt + 4096*i + 400; + for (j=0; j<40; j++) { writel(0x0000ff00, p); - p+=4; + p += 4; } } - /*carre rouge 40x40+100+10 */ + /* draw red rect 40x40+100+10 */ for (i=0; i<40; i++) { p = fbbase_virt + 4096 * (i+40) + 400; - for (j=0; j <40;j++) { - writel( 0x00ff0000, p); - p+=4; + for (j=0; j<40; j++) { + writel(0x00ff0000, p); + p += 4; } } } -#endif /* EN_24_32_BPP */ +#endif + + +#ifdef MODULE +module_init(sstfb_init); +module_exit(sstfb_exit); +#endif MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>"); MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards"); @@ -2087,57 +1737,3 @@ MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)"); MODULE_PARM(dev,"i"); MODULE_PARM_DESC(dev , "Attach to device ID (0..n) (default=1st device)"); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - -#if 1 -void __Dump_regs (struct sstfb_info * sst_info) -{ - struct { u32 reg ; char * reg_name;} pci_regs [] = { - { PCI_INIT_ENABLE, "initenable"}, - { PCI_VCLK_ENABLE, "enable vclk"}, - { PCI_VCLK_DISABLE, "disable vclk"}, - }; - - struct { u32 reg ; char * reg_name;} sst_regs [] = { - {FBIINIT0,"fbiinit0"}, - {FBIINIT1,"fbiinit1"}, - {FBIINIT2,"fbiinit2"}, - {FBIINIT3,"fbiinit3"}, - {FBIINIT4,"fbiinit4"}, - {FBIINIT5,"fbiinit5"}, - {FBIINIT6,"fbiinit6"}, - {FBIINIT7,"fbiinit7"}, - {LFBMODE,"lfbmode"}, - {FBZMODE,"fbzmode"}, - }; - int pci_s = sizeof(pci_regs)/sizeof(*pci_regs); - int sst_s = sizeof(sst_regs)/sizeof(*sst_regs); - u32 pci_res[pci_s]; - u32 sst_res[sst_s]; - - struct pci_dev * dev = sst_info->dev; - - int i; - - for (i=0; i < pci_s ; i++ ) { - pci_read_config_dword ( dev, pci_regs[i].reg , &pci_res[i]) ; - } - for (i=0; i < sst_s ; i++ ) { - sst_res[i]=sst_read(sst_regs[i].reg); - } - - dprintk ("Dump regs\n"); - for (i=0; i < pci_s ; i++ ) { - dprintk("%s = %0#10x\n", pci_regs[i].reg_name , pci_res[i]) ; - } - for (i=0; i < sst_s ; i++ ) { - dprintk("%s = %0#10x\n", sst_regs[i].reg_name , sst_res[i]) ; - } -} -#endif diff --git a/drivers/video/sstfb.h b/drivers/video/sstfb.h index f12d53177ab6..de66a85f6220 100644 --- a/drivers/video/sstfb.h +++ b/drivers/video/sstfb.h @@ -4,8 +4,6 @@ * Copyright (c) 2000,2001 Ghozlane Toumi <gtoumi@messel.emse.fr> * * Created 28 Aug 2001 by Ghozlane Toumi - * - * $Id: sstfb.h,v 1.8 2002/05/10 19:35:11 ghoz Exp $ */ @@ -25,7 +23,6 @@ # undef SST_DEBUG_REG # undef SST_DEBUG_FUNC # undef SST_DEBUG_VAR -# undef SST_DEBUG_IOCTL #endif #if (SST_DEBUG_REG > 0) @@ -73,8 +70,6 @@ #define wprintk(X...) printk(KERN_WARNING "sstfb: " X) #define BIT(x) (1ul<<(x)) -#define PS2KHZ(a) (1000000000UL/(a)) /* picoseconds to KHz */ -#define KHZ2PS(a) (1000000000UL/(a)) #define POW2(x) (1ul<<(x)) #ifndef ABS @@ -114,7 +109,11 @@ # define RD_BUFF_FRONT 0 /* read buff select (front) */ # define RD_BUFF_BACK (1 << 6) /* back */ # define EN_PXL_PIPELINE BIT(8) /* pixel pipeline (clip..)*/ +# define LFB_WORD_SWIZZLE_WR BIT(11) /* enable write-wordswap (big-endian) */ +# define LFB_BYTE_SWIZZLE_WR BIT(12) /* enable write-byteswap (big-endian) */ # define LFB_INVERT_Y BIT(13) /* invert Y origin (LFB) */ +# define LFB_WORD_SWIZZLE_RD BIT(15) /* enable read-wordswap (big-endian) */ +# define LFB_BYTE_SWIZZLE_RD BIT(16) /* enable read-byteswap (big-endian) */ #define CLIP_LEFT_RIGHT 0x0118 #define CLIP_LOWY_HIGHY 0x011c #define NOPCMD 0x0120 @@ -305,9 +304,9 @@ struct sstfb_info; struct dac_switch { char * name; - int (*detect) (struct sstfb_info *sst_info); - int (*set_pll) (struct sstfb_info *sst_info, const struct pll_timing *t, const int clock); - void (*set_vidmod) (struct sstfb_info *sst_info, const int bpp); + int (*detect) (struct fb_info *info); + int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock); + void (*set_vidmod) (struct fb_info *info, const int bpp); }; struct sst_spec { @@ -317,66 +316,21 @@ struct sst_spec { }; struct sstfb_par { - unsigned int bpp; - unsigned int xDim; /* xres */ + unsigned int yDim; unsigned int hSyncOn; /* hsync_len */ unsigned int hSyncOff; /* left_margin + xres + right_margin */ unsigned int hBackPorch;/* left_margin */ - unsigned int yDim; unsigned int vSyncOn; unsigned int vSyncOff; unsigned int vBackPorch; - unsigned int freq; /* freq in kHz */ struct pll_timing pll; unsigned int tiles_in_X;/* num of tiles in X res */ - unsigned int vmode; /* doublescan/interlaced */ - unsigned int sync; /* H/V sync polarity */ - unsigned int valid; /* par is correct (fool proof) */ -}; - -struct sstfb_info { - struct fb_info info; - struct sstfb_par current_par; - struct pci_dev * dev; - - struct { - unsigned long base; /* physical */ - unsigned long vbase; /* virtual (CPU view) */ - unsigned long len; - } video; /* fb memory info */ - struct { - unsigned long base; - unsigned long vbase; - } mmio; /* registers memory info */ - + unsigned long mmio_vbase; struct dac_switch dac_sw; /* dac specific functions */ - + struct pci_dev *dev; int type; u8 revision; - - /* status */ -/*XXX int configured; - int indexed_mode; - int vgapass; - int clipping; */ - int gfx_clock; - - int currcon; - struct display disp; /* current display */ - struct { u_int red, green, blue, transp; } palette[16]; - - union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef EN_24_32_BPP -#if defined (FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) - u32 cfb32[16]; -#endif -#endif - } fbcon_cmap; - + int gfx_clock; /* status */ }; - #endif /* _SSTFB_H_ */ diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h index 7e7e1546f6e7..d222f78cd9b4 100644 --- a/drivers/video/sticore.h +++ b/drivers/video/sticore.h @@ -83,8 +83,6 @@ extern struct sti_struct *sti_init_roms(void); there's no other way for stifb to find it. */ extern struct sti_struct *default_sti; -extern struct display_switch fbcon_sti; /* fbcon-sti.c */ - int sti_init_graph(struct sti_struct *sti); void sti_inq_conf(struct sti_struct *sti); void sti_putc(struct sti_struct *sti, int c, int y, int x); @@ -378,6 +376,9 @@ struct sti_struct { /* PCI data structures (pg. 17ff from sti.pdf) */ struct pci_dev *pd; u8 rm_entry[16]; /* pci region mapper array == pci config space offset */ + + /* pointer to the fb_info where this STI device is used */ + struct fb_info *info; }; diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index 27bf51f207bd..d64419f7fe4b 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -1,7 +1,7 @@ /* - * linux/drivers/video/sti/stifb.c - - * Frame buffer driver for HP workstations with STI (standard text interface) - * video firmware. + * linux/drivers/video/stifb.c - + * Low level Frame buffer driver for HP workstations with + * STI (standard text interface) video firmware. * * Copyright (C) 2001-2002 Helge Deller <deller@gmx.de> * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de> @@ -40,10 +40,9 @@ /* TODO: * - remove the static fb_info to support multiple cards - * - remove the completely untested 1bpp mode + * - 1bpp mode is completely untested * - add support for h/w acceleration * - add hardware cursor - * - */ @@ -59,30 +58,23 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> -#include <linux/tty.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> -#include <linux/selection.h> #include <linux/ioport.h> #include <linux/pci.h> -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb32.h> - #include <asm/grfioctl.h> /* for HP-UX compatibility */ #include "sticore.h" +/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */ #ifdef __LP64__ -/* return virtual address */ -#define REGION_BASE(fb_info, index) \ + #define REGION_BASE(fb_info, index) \ (fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000) #else -/* return virtual address */ -#define REGION_BASE(fb_info, index) \ + #define REGION_BASE(fb_info, index) \ fb_info->sti->glob_cfg->region_ptrs[index] #endif @@ -117,7 +109,6 @@ struct stifb_info { ngle_rom_t ngle_rom; struct sti_struct *sti; int deviceSpecificConfig; - struct display disp; }; static int stifb_force_bpp[MAX_STI_ROMS] = {0, }; @@ -901,7 +892,11 @@ stifb_setcolreg(u_int regno, u_int red, u_int green, if (regno >= 256) /* no. of hw registers */ return 1; - + + red >>= 8; + green >>= 8; + blue >>= 8; + START_IMAGE_COLORMAP_ACCESS(fb); if (fb->info.var.grayscale) { @@ -936,53 +931,6 @@ stifb_setcolreg(u_int regno, u_int red, u_int green, return 0; } -#if 0 -static void -stifb_loadcmap(struct stifb_info *fb) -{ - u32 color; - int i; - - if (!fb->cmap_reload) - return; - - START_IMAGE_COLORMAP_ACCESS(fb); - for (i = 0; i < 256; i++) { - if (fb->info.var.bits_per_pixel > 8) { - color = (i << 16) | (i << 8) | i; - } else { - if (fb->info.var.grayscale) { - /* gray = 0.30*R + 0.59*G + 0.11*B */ - color = ((fb->palette[i].red * 77) + - (fb->palette[i].green * 151) + - (fb->palette[i].blue * 28)) >> 8; - } else { - color = ((fb->palette[i].red << 16) | - (fb->palette[i].green << 8) | - (fb->palette[i].blue)); - } - } - WRITE_IMAGE_COLOR(fb, i, color); - } - if (fb->id == S9000_ID_HCRX) { - NgleLutBltCtl lutBltCtl; - - lutBltCtl = setHyperLutBltCtl(fb, - 0, /* Offset w/i LUT */ - 256); /* Load entire LUT */ - NGLE_BINC_SET_SRCADDR(fb, - NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); - /* 0x100 is same as used in WRITE_IMAGE_COLOR() */ - START_COLORMAPLOAD(fb, lutBltCtl.all); - SETUP_FB(fb); - } else { - /* cleanup colormap hardware */ - FINISH_IMAGE_COLORMAP_ACCESS(fb); - } - fb->cmap_reload = 0; -} -#endif - static int stifb_blank(int blank_mode, struct fb_info *info) { @@ -1075,32 +1023,24 @@ stifb_init_display(struct stifb_info *fb) static struct fb_ops stifb_ops = { .owner = THIS_MODULE, - .fb_set_var = gen_set_var, - .fb_get_cmap = gen_get_cmap, - .fb_set_cmap = gen_set_cmap, .fb_setcolreg = stifb_setcolreg, - /* .fb_pan_display = stifb_pan_display, */ .fb_blank = stifb_blank, - - /* .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - */ + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, }; - /* - * Initialization - */ +/* + * Initialization + */ int __init stifb_init_fb(struct sti_struct *sti, int force_bpp) { struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; - struct display *disp; - struct display_switch *dispsw; struct stifb_info *fb; struct fb_info *info; unsigned long sti_rom_address; @@ -1119,8 +1059,6 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) memset(fb, 0, sizeof(*fb)); fix = &info->fix; var = &info->var; - disp = &fb->disp; - info->disp = &fb->disp; fb->sti = sti; /* store upper 32bits of the graphics id */ @@ -1234,30 +1172,22 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) case 1: fix->type = FB_TYPE_PLANES; /* well, sort of */ fix->visual = FB_VISUAL_MONO10; - dispsw = &fbcon_sti; break; -#ifdef FBCON_HAS_CFB8 case 8: fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_PSEUDOCOLOR; - dispsw = &fbcon_cfb8; var->red.length = var->green.length = var->blue.length = 8; break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_TRUECOLOR; - dispsw = &fbcon_cfb32; var->red.length = var->green.length = var->blue.length = var->transp.length = 8; var->blue.offset = 0; var->green.offset = 8; var->red.offset = 16; var->transp.offset = 24; break; -#endif default: - dispsw = &fbcon_dummy; break; } @@ -1265,22 +1195,16 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) var->yres = var->yres_virtual = yres; var->bits_per_pixel = bpp; - strcpy(info->modename, "stifb"); + strcpy(fix->id, "stifb"); info->node = NODEV; info->fbops = &stifb_ops; info->screen_base = (void*) REGION_BASE(fb,1); - info->disp = disp; - info->changevar = NULL; - info->switch_con = gen_switch; - info->updatevar = &gen_update_var; info->flags = FBINFO_FLAG_DEFAULT; info->currcon = -1; /* This has to been done !!! */ fb_alloc_cmap(&info->cmap, 256, 0); stifb_init_display(fb); - gen_set_disp(-1, info); - disp->dispsw = dispsw; if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) { printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", @@ -1297,13 +1221,15 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) if (register_framebuffer(&fb->info) < 0) goto out_err3; + sti->info = info; /* save for unregister_framebuffer() */ + printk(KERN_INFO "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n", minor(fb->info.node), - fb->info.modename, - disp->var.xres, - disp->var.yres, - disp->var.bits_per_pixel, + fix->id, + var->xres, + var->yres, + var->bits_per_pixel, fb->id, fix->mmio_start); @@ -1315,6 +1241,7 @@ out_err3: out_err2: release_mem_region(fix->smem_start, fix->smem_len); out_err1: + fb_dealloc_cmap(&info->cmap); kfree(fb); return -ENXIO; } @@ -1325,7 +1252,6 @@ stifb_init(void) struct sti_struct *sti; int i; - if (sti_init_roms() == NULL) return -ENXIO; /* no STI cards available */ @@ -1346,7 +1272,17 @@ stifb_init(void) static void __exit stifb_cleanup(void) { - // unregister_framebuffer(); + struct sti_struct *sti; + int i; + + for (i = 0; i < MAX_STI_ROMS; i++) { + sti = sti_get_rom(i); + if (!sti) + break; + if (sti->info) + unregister_framebuffer(sti->info); + sti->info = NULL; + } } int __init diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 7a828918c948..b2437afe3455 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -166,6 +166,7 @@ static void tdfxfb_fillrect(struct fb_info *info, struct fb_fillrect *rect); static void tdfxfb_copyarea(struct fb_info *info, struct fb_copyarea *area); static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *image); static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor); +static int banshee_wait_idle(struct fb_info *info); static struct fb_ops tdfxfb_ops = { .owner = THIS_MODULE, @@ -318,7 +319,7 @@ static inline void banshee_make_room(struct tdfx_par *par, int size) while((tdfx_inl(par, STATUS) & 0x1f) < size); } -static inline void banshee_wait_idle(struct fb_info *info) +static int banshee_wait_idle(struct fb_info *info) { struct tdfx_par *par = (struct tdfx_par *) info->par; int i = 0; @@ -330,6 +331,7 @@ static inline void banshee_wait_idle(struct fb_info *info) i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1; if(i == 3) break; } + return 0; } /* @@ -758,7 +760,7 @@ static int tdfxfb_set_par(struct fb_info *info) break; } #endif - do_write_regs(par, ®); + do_write_regs(info, ®); /* Now change fb_fix_screeninfo according to changes in par */ info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3); @@ -1210,9 +1212,6 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); - /* clear framebuffer memory */ - memset_io(info->screen_base, 0, tdfx_fix.smem_len); - tdfx_fix.ypanstep = nopan ? 0 : 1; tdfx_fix.ywrapstep = nowrap ? 0 : 1; @@ -1223,11 +1222,13 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, info->pseudo_palette = (void *)(default_par + 1); info->flags = FBINFO_FLAG_DEFAULT; +#ifndef MODULE if (!mode_option) mode_option = "640x480@60"; err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) +#endif info->var = tdfx_var; size = (info->var.bits_per_pixel == 8) ? 256 : 16; diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 68d91b0cc847..6d79bd1c0232 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -329,9 +329,6 @@ static int vga16fb_release(struct fb_info *info, int user) static int vga16fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { -#ifdef FBCON_HAS_VGA - struct display *p = (info->currcon < 0) ? info->disp : (fb_display + info->currcon); -#endif struct vga16fb_par *par = (struct vga16fb_par *) info->par; u32 xres, right, hslen, left, xtotal; u32 yres, lower, vslen, upper, ytotal; @@ -368,20 +365,7 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var, mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB; maxmem = 16384; } - } -#ifdef FBCON_HAS_VGA - else if (var->bits_per_pixel == 0) { - int fh; - - shift = 3; - mode = MODE_TEXT; - fh = fontheight(p); - if (!fh) - fh = 16; - maxmem = 32768 * fh; - } -#endif - else + } else return -EINVAL; xres = (var->xres + 7) & ~7; @@ -548,42 +532,6 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var, } #undef FAIL -#ifdef FBCON_HAS_VGA -static void vga16fb_load_font(struct display* p) -{ - int chars; - unsigned char* font; - unsigned char* dest; - int chars; - - if (!p || !p->fontdata) - return; - chars = 256; - font = p->fontdata; - dest = vga16fb.screen_base; - - vga_io_wseq(0x00, 0x01); - vga_io_wseq(VGA_SEQ_PLANE_WRITE, 0x04); - vga_io_wseq(VGA_SEQ_MEMORY_MODE, 0x07); - vga_io_wseq(0x00, 0x03); - vga_io_wgfx(VGA_GFX_MODE, 0x00); - vga_io_wgfx(VGA_GFX_MISC, 0x04); - while (chars--) { - int i; - - for (i = fontheight(p); i > 0; i--) - writeb(*font++, dest++); - dest += 32 - fontheight(p); - } - vga_io_wseq(0x00, 0x01); - vga_io_wseq(VGA_SEQ_PLANE_WRITE, 0x03); - vga_io_wseq(VGA_SEQ_MEMORY_MODE, 0x03); - vga_io_wseq(0x00, 0x03); - vga_io_wgfx(VGA_GFX_MODE, 0x10); - vga_io_wgfx(VGA_GFX_MISC, 0x06); -} -#endif - static int vga16fb_set_par(struct fb_info *info) { struct vga16fb_par *par = (struct vga16fb_par *) info->par; @@ -690,10 +638,6 @@ static int vga16fb_set_par(struct fb_info *info) vga_io_wattr(i, atc[i]); } -#ifdef FBCON_HAS_VGA - if (par->mode & MODE_TEXT) - vga16fb_load_font(p); -#endif /* Wait for screen to stabilize. */ mdelay(50); @@ -1051,10 +995,6 @@ void vga16fb_fillrect(struct fb_info *info, struct fb_fillrect *rect) } else vga_8planes_fillrect(info, rect); break; -#ifdef FBCON_HAS_VGA - case FB_TYPE_TEXT: - break; -#endif case FB_TYPE_PACKED_PIXELS: default: cfb_fillrect(info, rect); @@ -1198,10 +1138,6 @@ void vga16fb_copyarea(struct fb_info *info, struct fb_copyarea *area) } else vga_8planes_copyarea(info, area); break; -#ifdef FBCON_HAS_VGA - case FB_TYPE_TEXT: - break; -#endif case FB_TYPE_PACKED_PIXELS: default: cfb_copyarea(info, area); @@ -1313,10 +1249,6 @@ void vga_imageblit_expand(struct fb_info *info, struct fb_image *image) } else vga_8planes_imageblit(info, image); break; -#ifdef FBCON_HAS_VGA - case FB_TYPE_TEXT: - break; -#endif case FB_TYPE_PACKED_PIXELS: default: cfb_imageblit(info, image); diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c index 39ebe6c36823..99ffe59f60cc 100644 --- a/drivers/video/vgastate.c +++ b/drivers/video/vgastate.c @@ -111,7 +111,7 @@ static void save_vga_text(struct vgastate *state, caddr_t fbbase) vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); for (i = 0; i < 8192; i++) - saved->vga_text[i] = vga_r(fbbase + 2 * 8192, i); + saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i); } /* restore regs */ @@ -184,7 +184,7 @@ static void restore_vga_text(struct vgastate *state, caddr_t fbbase) vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3); vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); - for (i = 0; i < 4 * 8192; i++) + for (i = 0; i < state->memsize; i++) vga_w(fbbase, i, saved->vga_font1[i]); } @@ -204,8 +204,7 @@ static void restore_vga_text(struct vgastate *state, caddr_t fbbase) vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); for (i = 0; i < 8192; i++) - vga_w(fbbase + 2 * 8192, i, - saved->vga_text[i]); + vga_w(fbbase, i, saved->vga_text[8192+i]); } /* unblank screen */ |
